* Date: 2018-4-3 */ namespace app\admin\controller; use think\Db; class Security extends Base { public $admin_info = array(); /** * 初始化操作 */ public function _initialize() { parent::_initialize(); $this->admin_info = session('admin_info'); } public function index() { // if (IS_POST) { // $this->handleSave(); // } $is_founder = 0; if (-1 == $this->admin_info['role_id'] && empty($this->admin_info['parent_id'])) { $is_founder = 1; } $this->admin_info['is_founder'] = $is_founder; $this->assign('admin_info', $this->admin_info); //自定义后台路径名 $baseFile = explode('/', $this->request->baseFile()); $web_adminbasefile = end($baseFile); $adminbasefile = preg_replace('/^(.*)\.([^\.]+)$/i', '$1', $web_adminbasefile); $this->assign('adminbasefile', $adminbasefile); // 安全验证配置 $security = tpSetting('security'); if (isset($security['security_verifyfunc'])) { $security['security_verifyfunc'] = json_decode($security['security_verifyfunc'], true); } $security_askanswer_content = ''; if (!empty($security['security_askanswer_list'])) { $security_askanswer_list = json_decode($security['security_askanswer_list'], true); $security['security_askanswer_list'] = $security_askanswer_list; } if (empty($security_askanswer_list)) { $security_askanswer_list = config('global.security_askanswer_list'); } $security_askanswer_content = implode(PHP_EOL, $security_askanswer_list); $this->assign('security', $security); $this->assign('security_askanswer_content', $security_askanswer_content); if (!empty($security['security_ask'])) { $security_ask = $security['security_ask']; if (!in_array($security_ask, $security_askanswer_list)) { $security_askanswer_list[] = $security_ask; } } $this->assign('security_askanswer_list', $security_askanswer_list); return $this->fetch(); } /** * 保存 - 全部(v1.6.2以下版本作废) * @return [type] [description] */ // private function handleSave() // { // // if (!empty($this->admin_info['parent_id']) || -1 != $this->admin_info['role_id']) { // // $this->error('该功能仅限于创始人操作!'); // // } // $post = input('post.'); // $settingData = []; // /*-------------------后台安全配置 start-------------------*/ // $param = [ // 'web_login_expiretime' => $post['web_login_expiretime'], // 'login_expiretime_old' => $post['login_expiretime_old'], // 'web_login_lockopen' => !empty($post['web_login_lockopen']) ? 1 : 0, // 'web_sqldatapath' => $post['web_sqldatapath'], // ]; // // 开启锁定才修改相应的配置值 // if (!empty($param['web_login_lockopen'])) { // $param['web_login_errtotal'] = $post['web_login_errtotal']; // $param['web_login_errexpire'] = $post['web_login_errexpire']; // } // // 自定义后台路径名 // $adminbasefile = preg_replace('/([^\w\_\-])/i', '', trim($post['adminbasefile'])).'.php'; // 新的文件名 // $param['web_adminbasefile'] = $this->root_dir.'/'.$adminbasefile; // 支持子目录 // $adminbasefile_old = preg_replace('/^(.*)\/([^\/]+)$/i', '${2}', tpCache('web.web_adminbasefile')); // 旧的文件名 // if ('index.php' == $adminbasefile) { // $this->error("后台路径禁止使用index", null, '', 1); // } // // 数据库备份目录 // $web_sqldatapath_old = tpCache('global.web_sqldatapath'); // $param['web_sqldatapath'] = '/'.trim($param['web_sqldatapath'], '/'); // // 后台登录超时 // $web_login_expiretime = $param['web_login_expiretime']; // $login_expiretime_old = $param['login_expiretime_old']; // unset($param['login_expiretime_old']); // if ($login_expiretime_old != $web_login_expiretime) { // $web_login_expiretime = preg_replace('/^(\d{0,})(.*)$/i', '${1}', $web_login_expiretime); // empty($web_login_expiretime) && $web_login_expiretime = config('login_expire'); // if ($web_login_expiretime > 2592000) { // $web_login_expiretime = 2592000; // 最多一个月 // } // $param['web_login_expiretime'] = $web_login_expiretime; // //前台登录超时时间 // $users_login_expiretime = getUsersConfigData('users.users_login_expiretime'); // //前台和后台谁设置的时间大就用谁的做session过期时间 // $max_login_expiretime = $web_login_expiretime; // if ($web_login_expiretime < $users_login_expiretime){ // $max_login_expiretime = $users_login_expiretime; // } // } // // 编辑器防注入 // $param['web_xss_filter'] = intval($post['web_xss_filter']); // /*-------------------后台安全配置 end-------------------*/ // /*-------------------二次安全验证 start-------------------*/ // $this->handleAskData($settingData, $post); // /*-------------------二次安全验证 end-------------------*/ // /*多语言*/ // if (is_language()) { // $langRow = \think\Db::name('language')->order('id asc') // ->cache(true, EYOUCMS_CACHE_TIME, 'language') // ->select(); // foreach ($langRow as $key => $val) { // tpCache('web', $param, $val['mark']); // tpSetting('security', $settingData, $val['mark']); // } // } else { // tpCache('web', $param); // tpSetting('security', $settingData); // } // /*--end*/ // $refresh = false; // /*-------------------后台安全配置 start-------------------*/ // // 更改session会员设置 - session有效期(后台登录超时) // if ($login_expiretime_old != $web_login_expiretime) { // $session_conf = []; // $session_file = APP_PATH.'admin/conf/session_conf.php'; // if (file_exists($session_file)) { // require_once($session_file); // $session_conf_tmp = EY_SESSION_CONF; // if (!empty($session_conf_tmp)) { // $session_conf_tmp = json_decode($session_conf_tmp, true); // if (!empty($session_conf_tmp) && is_array($session_conf_tmp)) { // $session_conf = $session_conf_tmp; // } // } // } // $session_conf['expire'] = $max_login_expiretime; // $str_session_conf = 'domain().$this->root_dir.'/'.$adminbasefile; // 支持子目录 // if ($adminbasefile_old != $adminbasefile && eyPreventShell($adminbasefile_old)) { // if (file_exists($adminbasefile_old)) { // if(rename($adminbasefile_old, $adminbasefile)) { // $refresh = true; // } // } else { // $this->error("根目录{$adminbasefile_old}文件不存在!", null, '', 2); // } // } // if ($web_sqldatapath_old != $param['web_sqldatapath'] && preg_match('/^\/data\/sqldata([^\/]*)$/i', $param['web_sqldatapath'])) { // @rename(ROOT_PATH.ltrim($web_sqldatapath_old, '/'), ROOT_PATH.ltrim($param['web_sqldatapath'], '/')); // } // /*-------------------后台安全配置 end-------------------*/ // if ($refresh) { // $this->success('操作成功', $gourl, '', 1, [], '_parent'); // } // $this->success('操作成功', url('Security/index')); // } /** * 保存 - 后台安全中心 * @return [type] [description] */ public function handleSave1() { if (IS_POST) { $post = input('post.'); $settingData = []; /*-------------------后台安全配置 start-------------------*/ $param = [ 'web_login_expiretime' => $post['web_login_expiretime'], 'login_expiretime_old' => $post['login_expiretime_old'], 'web_login_lockopen' => !empty($post['web_login_lockopen']) ? 1 : 0, 'web_sqldatapath' => $post['web_sqldatapath'], ]; // 开启锁定才修改相应的配置值 if (!empty($param['web_login_lockopen'])) { $param['web_login_errtotal'] = $post['web_login_errtotal']; $param['web_login_errexpire'] = $post['web_login_errexpire']; } // 自定义后台路径名 $adminbasefile = preg_replace('/([^\w\_\-])/i', '', trim($post['adminbasefile'])).'.php'; // 新的文件名 $param['web_adminbasefile'] = $this->root_dir.'/'.$adminbasefile; // 支持子目录 $baseFile = explode('/', $this->request->baseFile()); $adminbasefile_old = end($baseFile); // 旧的文件名 if ('index.php' == $adminbasefile) { $this->error("后台路径禁止使用index", null, '', 1); } // 数据库备份目录 $web_sqldatapath_old = tpCache('global.web_sqldatapath'); $param['web_sqldatapath'] = '/'.trim($param['web_sqldatapath'], '/'); // 后台登录超时 $web_login_expiretime = $param['web_login_expiretime']; $login_expiretime_old = $param['login_expiretime_old']; unset($param['login_expiretime_old']); if ($login_expiretime_old != $web_login_expiretime) { $web_login_expiretime = preg_replace('/^(\d{0,})(.*)$/i', '${1}', $web_login_expiretime); empty($web_login_expiretime) && $web_login_expiretime = config('login_expire'); if ($web_login_expiretime > 2592000) { $web_login_expiretime = 2592000; // 最多一个月 } $param['web_login_expiretime'] = $web_login_expiretime; //前台登录超时时间 $users_login_expiretime = getUsersConfigData('users.users_login_expiretime'); //前台和后台谁设置的时间大就用谁的做session过期时间 $max_login_expiretime = $web_login_expiretime; if ($web_login_expiretime < $users_login_expiretime){ $max_login_expiretime = $users_login_expiretime; } } // 编辑器防注入 $param['web_xss_filter'] = intval($post['web_xss_filter']); // 网站防止被刷 $param['web_anti_brushing'] = intval($post['web_anti_brushing']); /*-------------------后台安全配置 end-------------------*/ /*多语言*/ if (is_language()) { $langRow = \think\Db::name('language')->order('id asc') ->cache(true, EYOUCMS_CACHE_TIME, 'language') ->select(); foreach ($langRow as $key => $val) { tpCache('web', $param, $val['mark']); } } else { tpCache('web', $param); } /*--end*/ $refresh = false; /*-------------------后台安全配置 start-------------------*/ // 更改session会员设置 - session有效期(后台登录超时) if ($login_expiretime_old != $web_login_expiretime) { $session_conf = []; $session_file = APP_PATH.'admin/conf/session_conf.php'; if (file_exists($session_file)) { require_once($session_file); $session_conf_tmp = EY_SESSION_CONF; if (!empty($session_conf_tmp)) { $session_conf_tmp = json_decode($session_conf_tmp, true); if (!empty($session_conf_tmp) && is_array($session_conf_tmp)) { $session_conf = $session_conf_tmp; } } } $session_conf['expire'] = $max_login_expiretime; $str_session_conf = 'domain().$this->root_dir.'/'.$adminbasefile; // 支持子目录 if ($adminbasefile_old != $adminbasefile && eyPreventShell($adminbasefile_old)) { if (file_exists($adminbasefile_old)) { if(rename($adminbasefile_old, $adminbasefile)) { $refresh = true; } } else { $this->error("根目录{$adminbasefile_old}文件不存在!", null, '', 2); } } if ($web_sqldatapath_old != $param['web_sqldatapath'] && preg_match('/^\/data\/sqldata([^\/]*)$/i', $param['web_sqldatapath'])) { @rename(ROOT_PATH.ltrim($web_sqldatapath_old, '/'), ROOT_PATH.ltrim($param['web_sqldatapath'], '/')); } /*-------------------后台安全配置 end-------------------*/ if ($refresh) { $this->success('操作成功', $gourl, '', 1, [], '_parent'); } $this->success('操作成功', url('Security/index')); } $this->error('操作失败'); } /** * 保存 - 安全验证中心 * @return [type] [description] */ public function handleSave2() { if (IS_POST) { $settingData = []; $post = input('post.'); if (empty($post['security_ask_open'])) { $securityOld = tpSetting('security'); if (!empty($securityOld['security_ask'])) { $answer = empty($post['security_answer_old']) ? '' : trim($post['security_answer_old']); if (empty($answer)) { $this->error('请录入密保答案!'); } else { $security_answer = empty($securityOld['security_answer']) ? '' : trim($securityOld['security_answer']); $encrypt_answer = func_encrypt($answer, true, pwd_encry_type('bcrypt')); if ($security_answer != $encrypt_answer) { $this->error('密保答案不正确!'); } } $this->submit_answer_verify(); } } /*-------------------二次安全验证 start-------------------*/ $this->handleAskData($settingData, $post); /*-------------------二次安全验证 end-------------------*/ /*多语言*/ if (is_language()) { $langRow = \think\Db::name('language')->order('id asc') ->cache(true, EYOUCMS_CACHE_TIME, 'language') ->select(); foreach ($langRow as $key => $val) { tpSetting('security', $settingData, $val['mark']); } } else { tpSetting('security', $settingData); } /*--end*/ // 设置问题答案后,自动验证通过 $this->submit_answer_verify(); $msg = "操作成功"; $is_show_answer = 0; if (!empty($settingData['security_answer']) && !empty($settingData['security_ask_open'])) { $is_show_answer = 1; $securityData = tpSetting('security'); $msg = "问题:{$securityData['security_ask']}
答案:".mchStrCode($securityData['security_answer_bright'], 'DECODE'); } $this->success($msg, url('Security/index'), ['is_show_answer'=>$is_show_answer,'security_ask_open'=>$settingData['security_ask_open']]); } $this->error('操作失败'); } /** * 保存二次安全验证的数据处理 * @param array &$settingData [description] * @param array &$post [description] * @return [type] [description] */ private function handleAskData(&$settingData = [], &$post = []) { $securityOld = tpSetting('security'); $security_ask = intval($post['security_ask']); $security_answer = trim($post['security_answer']); $is_ask_add_edit = empty($securityOld['security_ask']) ? 'add' : 'edit'; if ('add' == $is_ask_add_edit) { if (empty($post['security_ask_open'])) { $this->success('操作成功', url('Security/index'), ['is_show_answer'=>0,'security_ask_open'=>0]); } if (0 > intval($security_ask)) { $this->error('请选择密保问题!'); } else if ($security_answer === '') { $this->error('请设置密保答案!'); } $encrypt_answer = func_encrypt($security_answer, true, pwd_encry_type('bcrypt')); $row = Db::name('admin')->where([ 'admin_id' => $this->admin_info['admin_id'], 'password' => $encrypt_answer, ])->count(); if (!empty($row)) { $this->error('密保答案不能与登录密码一致!'); } } else { $security_answer_old = trim($post['security_answer_old']); if ($security_answer !== '' || 0 <= intval($security_ask)) { if ($security_answer_old === '') { $this->error('密保答案不能为空!'); } else { if (0 <= intval($security_ask)) { if ($security_answer === '') { $this->error('请重置密保答案!'); } else if ($security_answer === $security_answer_old) { $this->error('重置密保答案不能与原来的一致!'); } } } $encrypt_answer_old = func_encrypt($security_answer_old, true, pwd_encry_type('bcrypt')); if ($encrypt_answer_old != $securityOld['security_answer']) { $this->error('密保答案不正确!'); } $encrypt_answer = func_encrypt($security_answer, true, pwd_encry_type('bcrypt')); $row = Db::name('admin')->where([ 'admin_id' => $this->admin_info['admin_id'], 'password' => $encrypt_answer, ])->count(); if (!empty($row)) { $this->error('重置密保答案不能与登录密码一致!'); } } else { if ($security_answer_old !== '') { $encrypt_answer_old = func_encrypt($security_answer_old, true, pwd_encry_type('bcrypt')); if ($encrypt_answer_old != $securityOld['security_answer']) { $this->error('密保答案不正确!'); } } unset($post['security_ask']); unset($post['security_answer']); unset($post['security_answer_old']); } } /** * 如果要关闭二次安全验证,必须要进行答案验证 * 同IP不验证功能也会影响到这里的逻辑 */ // 问题列表 $security_askanswer_list = empty($securityOld['security_askanswer_list']) ? config('global.security_askanswer_list') : json_decode($securityOld['security_askanswer_list'], true); // 当前管理员二次安全验证过的IP地址 $security_answerverify_ip = !empty($securityOld['security_answerverify_ip']) ? $securityOld['security_answerverify_ip'] : '-1'; // 1、问答要已设置;2、目前是开启;3、当前要关闭; if (!empty($securityOld['security_ask_open']) && empty($post['security_ask_open']) && !empty($securityOld['security_ask'])) { $admin_info = Db::name('admin')->field('*')->where(['admin_id'=>$this->admin_info['admin_id']])->find(); // if (!empty($admin_info['parent_id']) || -1 != $admin_info['role_id']) { // $this->error('创始人才能关闭安全验证功能!'); // } if ($admin_info['last_ip'] != $security_answerverify_ip) { $this->error("__html__出于安全考虑
请勿非法越过密保答案验证", null, '', 3); } } $settingData['security_ask_open'] = intval($post['security_ask_open']); if (!empty($settingData['security_ask_open'])) { $post['security_verifyfunc'][] = 'Filemanager@*'; $post['security_verifyfunc'][] = 'Arctype@ajax_newtpl'; $post['security_verifyfunc'][] = 'Archives@ajax_newtpl'; // $post['security_verifyfunc'][] = 'Security@*'; $post['security_verifyfunc'] = array_unique($post['security_verifyfunc']); $settingData['security_verifyfunc'] = json_encode($post['security_verifyfunc']); $settingData['security_ask_ip_open'] = !empty($post['security_ask_ip_open']) ? intval($post['security_ask_ip_open']) : 0; if (isset($post['security_ask'])) { $settingData['security_ask'] = $security_askanswer_list[$post['security_ask']]; } if (isset($post['security_answer'])) { $settingData['security_answer'] = func_encrypt($post['security_answer'], true, pwd_encry_type('bcrypt')); $settingData['security_answer_bright'] = mchStrCode($post['security_answer']); } if (empty($securityOld['security_askanswer_list'])) { $settingData['security_askanswer_list'] = json_encode($security_askanswer_list); } } } /*--------------------------------安全验证中心 start--------------------------*/ /** * 设置二次安全验证的问题、答案 */ public function second_verify_add() { $security_askanswer_list = tpSetting('security.security_askanswer_list'); $security_askanswer_list = json_decode($security_askanswer_list, true); if (empty($security_askanswer_list)) { $security_askanswer_list = config('global.security_askanswer_list'); } if (IS_POST) { // 修补越权的漏洞,在重设答案时,通过抓包改成新设答案 if (!empty($this->globalConfig['security_ask'])) { $this->error('已设置过密保,请重新设置'); } $ask = input('post.ask/d'); $answer = input('post.answer/s'); $answer = trim($answer); if (0 > $ask) { $this->error('请选择密保问题!'); } else if (empty($answer)) { $this->error('密保答案不能为空!'); } $encrypt_answer = func_encrypt($answer, true, pwd_encry_type('bcrypt')); $row = Db::name('admin')->where([ 'admin_id' => $this->admin_info['admin_id'], 'password' => $encrypt_answer, ])->count(); if (!empty($row)) { $this->error('密保答案不能与登录密码一致!'); } $data = [ 'security_ask_open' => 1, 'security_ask' => $security_askanswer_list[$ask], 'security_answer' => $encrypt_answer, 'security_answer_bright' => mchStrCode($answer), 'security_askanswer_list' => json_encode($security_askanswer_list), ]; /*多语言*/ if (is_language()) { $langRow = \think\Db::name('language')->order('id asc') ->cache(true, EYOUCMS_CACHE_TIME, 'language') ->select(); foreach ($langRow as $key => $val) { tpSetting('security', $data, $val['mark']); } } else { tpSetting('security', $data); } /*--end*/ $this->success('操作成功', url('Security/index')); } $this->assign('security_askanswer_list', $security_askanswer_list); return $this->fetch(); } /** * 修改二次安全验证的问题、答案 */ public function second_verify_edit() { $security_askanswer_list = tpSetting('security.security_askanswer_list'); $security_askanswer_list = json_decode($security_askanswer_list, true); if (empty($security_askanswer_list)) { $security_askanswer_list = config('global.security_askanswer_list'); } if (IS_POST) { $post = input('post.'); $answer_old = trim($post['answer_old']); $ask = intval($post['ask']); $answer = trim($post['answer']); if (empty($answer_old)) { $this->error('密保答案不能为空!'); } else { if (0 <= $ask) { if (empty($answer)) { $this->error('重置密保答案不能为空!'); } else if ($answer == $answer_old) { $this->error('重置密保答案不能与原来的一致!'); } } } $security = tpSetting('security'); $encrypt_answer_old = func_encrypt($answer_old, true, pwd_encry_type('bcrypt')); if ($encrypt_answer_old != $security['security_answer']) { $this->error('密保答案不正确!'); } $data = []; if (0 <= $ask) { $encrypt_answer = func_encrypt($answer, true, pwd_encry_type('bcrypt')); $row = Db::name('admin')->where([ 'admin_id' => $this->admin_info['admin_id'], 'password' => $encrypt_answer, ])->count(); if (!empty($row)) { $this->error('重置密保答案不能与登录密码一致!'); } $data['security_ask'] = $security_askanswer_list[$ask]; $data['security_answer'] = $encrypt_answer; $data['security_answer_bright'] = mchStrCode($answer); $data['security_askanswer_list'] = json_encode($security_askanswer_list); } if (!empty($data)) { /*多语言*/ if (is_language()) { $langRow = \think\Db::name('language')->order('id asc') ->cache(true, EYOUCMS_CACHE_TIME, 'language') ->select(); foreach ($langRow as $key => $val) { tpSetting('security', $data, $val['mark']); } } else { tpSetting('security', $data); } /*--end*/ } $this->success('操作成功', url('Security/index')); } $security = tpSetting('security'); if (!empty($security)) { $security_ask = $security['security_ask']; if (!in_array($security_ask, $security_askanswer_list)) { $security_askanswer_list[] = $security_ask; } } $this->assign('security', $security); $this->assign('security_askanswer_list', $security_askanswer_list); return $this->fetch(); } /** * 二次安全验证答案 * @return [type] [description] */ public function ajax_answer_verify() { if (IS_POST) { $answer = input('param.answer/s'); $answer = trim($answer); if (empty($answer)) { $this->error('请录入密保答案!'); } else { $security_answer = tpSetting('security.security_answer'); $encrypt_answer = func_encrypt($answer, true, pwd_encry_type('bcrypt')); if ($security_answer != $encrypt_answer) { $this->error('密保答案不正确!'); } } $this->submit_answer_verify(); $this->success('密保验证成功'); } } /** * 二次安全验证答案-提交 * @return [type] [description] */ private function submit_answer_verify() { /*多语言*/ $ip = clientIP(); if (is_language()) { $langRow = \think\Db::name('language')->order('id asc') ->cache(true, EYOUCMS_CACHE_TIME, 'language') ->select(); foreach ($langRow as $key => $val) { tpSetting('security', ['security_answerverify_ip'=>$ip], $val['mark']); } } else { tpSetting('security', ['security_answerverify_ip'=>$ip]); } /*--end*/ // 解决个别用户安装后,登录后台没记录最后登录IP地址,导致一直弹出验证答案 $admin_info = Db::name('admin')->field('admin_id,last_ip')->where(['admin_id'=>$this->admin_info['admin_id']])->find(); Db::name('admin')->where(['admin_id'=>$admin_info['admin_id']])->save(['last_ip'=>$ip, 'update_time'=>getTime()]); } /** * 是否已验证了答案 * @return [type] [description] */ public function ajax_isverify_answer() { if (IS_POST) { $security = tpSetting('security'); $security_answerverify_ip = !empty($security['security_answerverify_ip']) ? $security['security_answerverify_ip'] : '-1'; $admin_info = Db::name('admin')->field('admin_id,last_ip')->where(['admin_id'=>$this->admin_info['admin_id']])->find(); if ($admin_info['last_ip'] == $security_answerverify_ip) { $this->success('已验证'); } } $this->error('未验证'); } /** * 修改问题列表 * @return [type] [description] */ public function save_ask_list() { if (IS_POST) { $value = input('post.value/s'); $value = str_replace(["\r\n", "\n\r", "\r", "\n"], PHP_EOL, $value); $arr = explode(PHP_EOL, $value); foreach ($arr as $key => $val) { $val = trim($val); if (empty($val)) { unset($arr[$key]); } else { $arr[$key] = $val; } } if (empty($arr)) { $this->error('问题列表不能为空!'); } // 将已设置的问题加入列表中 $security_ask = tpSetting('security.security_ask'); $security_ask = trim($security_ask); if (!empty($security_ask) && !in_array($security_ask, $arr)) { $arr[] = $security_ask; } if (is_language()) { $langRow = Db::name('language')->order('id asc')->select(); foreach ($langRow as $key => $val) { tpSetting('security', ['security_askanswer_list'=>json_encode($arr)], $val['mark']); } } else { // 单语言 tpSetting('security', ['security_askanswer_list'=>json_encode($arr)]); } $value = implode(PHP_EOL, $arr); $this->success('操作成功', null, ['value'=>$value, 'security_askanswer_list'=>$arr]); } } /** * 独立弹窗的安全验证中心(用于点击入口模板管理) * @return [type] [description] */ public function second_ask_init() { if (IS_POST) { $settingData = []; $post = input('post.'); /*-------------------二次安全验证 start-------------------*/ $this->handleAskData($settingData, $post); /*-------------------二次安全验证 end-------------------*/ /*多语言*/ if (is_language()) { $langRow = \think\Db::name('language')->order('id asc') ->cache(true, EYOUCMS_CACHE_TIME, 'language') ->select(); foreach ($langRow as $key => $val) { tpSetting('security', $settingData, $val['mark']); } } else { tpSetting('security', $settingData); } /*--end*/ // 设置问题答案后,自动验证通过 $this->submit_answer_verify(); $is_show_answer = 0; if (empty($settingData['security_ask_open'])) { $gourl = ""; $msg = "操作成功"; } else { $gourl = input('param.gourl/s', '', null); if (empty($settingData['security_answer'])) { $msg = "操作成功"; } else { $is_show_answer = 1; $securityData = tpSetting('security'); $msg = "问题:{$securityData['security_ask']}
答案:".mchStrCode($securityData['security_answer_bright'], 'DECODE'); } } $this->success($msg, null, ['gourl'=>$gourl,'is_show_answer'=>$is_show_answer]); } $is_founder = 0; if (-1 == $this->admin_info['role_id'] && empty($this->admin_info['parent_id'])) { $is_founder = 1; } $this->admin_info['is_founder'] = $is_founder; $this->assign('admin_info', $this->admin_info); // 安全验证配置 $security = tpSetting('security'); if (!isset($security['security_ask_open'])) { $security['security_ask_open'] = 1; } if (isset($security['security_verifyfunc'])) { $security['security_verifyfunc'] = json_decode($security['security_verifyfunc'], true); } $security_askanswer_content = ''; if (!empty($security['security_askanswer_list'])) { $security_askanswer_list = json_decode($security['security_askanswer_list'], true); $security['security_askanswer_list'] = $security_askanswer_list; } if (empty($security_askanswer_list)) { $security_askanswer_list = config('global.security_askanswer_list'); } $security_askanswer_content = implode(PHP_EOL, $security_askanswer_list); $this->assign('security', $security); $this->assign('security_askanswer_content', $security_askanswer_content); if (!empty($security['security_ask'])) { $security_ask = $security['security_ask']; if (!in_array($security_ask, $security_askanswer_list)) { $security_askanswer_list[] = $security_ask; } } $this->assign('security_askanswer_list', $security_askanswer_list); $gourl = input('param.gourl/s'); $this->assign('gourl', urldecode($gourl)); // 点击来源 $source = input('param.source/s'); $this->assign('source', $source); return $this->fetch(); } public function ajax_security_ask_open() { $data = tpSetting('security'); $data['security_ask_open'] = empty($data['security_ask_open']) ? 0 : intval($data['security_ask_open']); $this->success('请求成功', null, $data); } /*-----------------------ddos攻击脚本查杀 start-----------------------*/ /** * DDOS攻击脚本查杀 * @return [type] [description] */ public function ddos_kill() { $Prefix = config('database.prefix'); $isTable = Db::query('SHOW TABLES LIKE \''.$Prefix.'ddos_log\''); if (empty($isTable)) { $tableSql = << ROOT_PATH, ]; $this->assign($assign); return $this->fetch(); } /** * 扫描 * @return [type] [description] */ public function ddos_scan() { //防止超时/内存溢出 function_exists('set_time_limit') && set_time_limit(0); @ini_set('memory_limit','-1'); \think\Session::pause(); // 暂停session,防止session阻塞机制 if (IS_POST) { Db::name('ddos_log')->where(['id'=>['gt',0]])->delete(); $start=getTime(); $list = []; $html = ''; $dir = ROOT_PATH; if (!is_readable($dir)) { $dir = str_replace('\\', '/', $dir); $dir = rtrim($dir, '/').'/'; } $total = $num_ky = $scanned = 0; $auth_code = tpCache('system.system_auth_code'); $this->ddos_getDirFile($dir, '', $list, $total); foreach ($list as $key => $value) { $md5key = md5($value.$auth_code); $fd = realpath($value); $fp = fopen($fd, "r"); $scanned +=1; $i = 0; $is_suspicious = 0; while ($buffer = fgets($fp, 4096)) { $i++; if ($this->ddos_checkCodeFeatures($buffer)) { $num_ky += 1; $j = $num_ky % 2 + 1; $buffer = htmlspecialchars($this->ddos_cut_str($buffer,120,0)); $is_suspicious = 1; $html .= << {$num_ky} {$fd} 第 {$i} 行 {$buffer} 删除 EOF; } } fclose($fp); Db::name('ddos_log')->insert([ 'md5key' => $md5key, 'file_name' => base64_encode($value), 'file_num' => $scanned, 'file_total' => $total, 'file_num_ky' => $num_ky, 'is_suspicious'=>$is_suspicious, 'html' => empty($html) ? '' : htmlspecialchars($html), 'add_time' => getTime(), ]); } $end = getTime(); $spent = ($end - $start); $spent_str = ''; $hours = intval($spent/3600); if (!empty($hours)) { $spent_str .= $hours."小时"; } if ($spent >= 60) { $spent_str .= gmdate('i分', $spent); } $spent_str .= gmdate('s秒', $spent); if (empty($num_ky)) { $html = << 没有发现可疑文件 EOF; } $data = [ 'scanned' => $scanned, 'num_ky' => $num_ky, 'spent' => $spent_str, 'html' => $html, ]; $this->success("扫描完成,请自己排查处理", null, $data); } } /** * 是否是可疑恶意文件 * @param string $buffer [description] * @return [type] [description] */ private function ddos_checkCodeFeatures($buffer = '') { $bool = false; if (!empty($buffer)) { if ( preg_match('/(pfsoc'.'kopen|fsoc'.'kopen)\("(udp|tcp)/i', $buffer) || preg_match('/Php(\s+)(\d+)(\s+)Termi'.'nator/i', $buffer) || preg_match('/[\$_G'.'ET|\$_REQU'.'EST]\[\'rat\']/i', $buffer) || preg_match('/Tcp3(\s+)CC\.center/i', $buffer) || preg_match('/xdos\.s/i', $buffer) || preg_match('/儏摓煁'.'晜泟/i', $buffer) || preg_match('/((FilemanagerModel\.php)|(\$qaz(\s*)=(\s*)\$qwe)|(include(\s*)\((\s*)([\"\']+)\/tmp\/)|(\$content'.'_mb(\s*)=(\s*))|(file_get_contents(\s*)\((\s*)\$auth_role_admin(\s*)\)))/i', $buffer) || preg_match('/function(\s+)httpGetlai\(/i', $buffer) ) { $bool = true; } } return $bool; } private function ddos_cut_str($string, $sublen, $start = 0, $code = 'UTF-8') { if ($code == 'UTF-8') { $pa = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xef][\x80-\xbf][\x80-\xbf]|\xf0[\x90-\xbf][\x80-\xbf][\x80-\xbf]|[\xf1-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf]/"; preg_match_all($pa, $string, $t_string); if (count($t_string[0]) - $start > $sublen) { return join('', array_slice($t_string[0], $start, $sublen)) . "..."; } return join('', array_slice($t_string[0], $start, $sublen)); } else { $start = $start * 2; $sublen = $sublen * 2; $strlen = strlen($string); $tmpstr = ''; for($i = 0; $i < $strlen; $i++) { if ($i >= $start && $i < ($start + $sublen)) { if (ord(substr($string, $i, 1)) > 129) { $tmpstr .= substr($string, $i, 2); } else { $tmpstr .= substr($string, $i, 1); } } if (ord(substr($string, $i, 1)) > 129) { $i++; } } if (strlen($tmpstr) < $strlen) { $tmpstr .= "..."; } return $tmpstr; } } /** * 递归读取文件夹文件 */ private function ddos_getDirFile($directory, $dir_name = '', &$arr_file = array(), &$total = 0) { $self = '';//'Security.php'; $mydir = dir($directory); while ($file = $mydir->read()) { if ((is_dir("$directory/$file")) && !in_array($file, ['.','..','uploads'])) { if ($dir_name) { $this->ddos_getDirFile("$directory/$file", "$dir_name/$file", $arr_file, $total); } else { $this->ddos_getDirFile("$directory/$file", "$file", $arr_file, $total); } } else { if($file != $self){ if (!in_array($file, ['.','..','uploads']) && preg_match("/\.(php|htm|asp|jsp)$/i", $file)) { $total +=1; if ($dir_name) { $arr_file[] = "$dir_name/$file"; } else { $arr_file[] = "$file"; } } } } } $mydir->close(); return $arr_file; } /** * 扫描进度 * @return [type] [description] */ public function ddos_progressd() { \think\Session::pause(); // 暂停session,防止session阻塞机制 if (IS_AJAX) { $progress = 0; $result = []; $init = input('param.init/d'); if (empty($init)) { Db::name('ddos_log')->where(['id'=>['gt',0]])->delete(); } else { $result = Db::name('ddos_log')->field('id, file_num, file_total, file_num_ky, html')->order('id desc')->find(); } if (!empty($result)) { $progress = $result['file_num'] / $result['file_total']; $progress = floor($progress*100)/100; if ($progress >= 1) { Db::name('ddos_log')->where(['id'=>['gt',0], 'is_suspicious'=>0])->delete(); } $progress = strval($progress * 100); if (empty($result['file_num_ky'])) { $html = << 正在扫描中 EOF; } else { $html = htmlspecialchars_decode($result['html']); } $this->success('请求成功', null, ['progress'=>$progress,'file_num'=>$result['file_num'],'file_num_ky'=>$result['file_num_ky'],'html'=>$html]); } else { $this->success('请求成功', null, ['progress'=>$progress]); } } } /** * 删除可疑恶意文件 * @return [type] [description] */ public function ddos_delfile() { if (IS_AJAX) { $md5key = input('param.md5key/s'); $result = Db::name('ddos_log')->where(['md5key'=>$md5key, 'is_suspicious'=>1])->find(); if (empty($result)) { $this->success('操作成功'); } $filename = !empty($result['file_name']) ? trim($result['file_name'], '/') : ''; if (!empty($filename) && is_file($filename)) { $filetype = pathinfo($filename, PATHINFO_EXTENSION); $phpfile = strtolower(stristr($filename,'.php')); if ($phpfile || in_array($filetype, ['php','js','png','gif','jpg','jpeg','ico','bmp','webp','htm','asp','jsp'])) { $fd = realpath($filename); $fp = fopen($fd, "r"); $num_ky = 0; while ($buffer = fgets($fp, 4096)) { if ($this->ddos_checkCodeFeatures($buffer)) { $num_ky = 1; break; } } fclose($fp); if (!empty($num_ky)) { @unlink('./'.$filename); $this->success('操作成功'); } } } } $this->error('操作失败'); } /*-----------------------ddos攻击脚本查杀 end-----------------------*/ }