WordPress 安全:限制同 IP 对 admin-ajax、wp-login 等任意 URL 的访问频率

编辑于:2022年01月04日

WordPress 安全:限制同 IP 对 admin-ajax、wp-login 等任意 URL 的访问频率

限制对 WordPress 特定网址的访问频率,比如一个 IP 地址每秒只能访问一次,每分钟一次,甚至每小时一次,可以有利避免对 wp-login.php 进行暴力破解登录、对 admin-ajax.php 恶意提交文章评论、刷手机短信验证码,以及 CC 攻击你的 API 接口等。

当限制请求次数在 1 分钟 1 次之内时,比如:1 分钟 1 次、 1秒 1 次、20 秒 1 次,推荐 使用 Nginx 限制访问频率。当限制频率超过了 1 分钟 1 次,比如 20 分钟 5 次、2 小时 3 次时,就要使用如下方法了。

准备工作

为了提高性能,代码使用了 memcached 缓存数据到服务器的内存,因此你的服务器必须安装 memcached 。宝塔面板—— PHP——扩展选项,找到 memcached 点击安装, 注意看最后一个字母是 dPHP 版安装就绪,再去软件商店搜一下,确认软件版的是否也已安装。

代码部署

代码分为两部分,第一部分是自定义一个控制访问频率的函数,第二部分是使用WordPress 动作钩子,将频率控制函数挂在到所需要控制页面 PHP 上。原理不懂没事,只要你明白步骤分两步走就行。

第一步:添加频率控制函数

你可以自行调整防刷新时间、次数、警告次数、解封时间等,在代码中用 // 对关键内容做了注释,一看就能明白在哪里修改。

/**
 * 使用教程:https://www.cccitu.com/5079.html
 * 限制URL访问频率的函数,对管理员登录状态以外的访问起效
 * 可以通过动作钩子引用此函数,限制特定的页面
 * 该函数主要参考了https://www.tjit.net/194.html
 */
function cccitu_waf() {
    if(!current_user_can( 'manage_options' )){ //对登录后的网站管理员访问不起作用。该函数是 WordPress 网站独有,非 WordPress 请不要使用此判断
        ini_set("display_errors", "Off");
            error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);
            extension_loaded('memcached') or die('memcached扩展未安装!');
            $logPath = $_SERVER['DOCUMENT_ROOT'] . '/cccitu-waf/cccitu-waf.log'; //日志记录文件保存路径,在网站根目录的 cccitu-waf 文件内内可以查看
            $fileht = $_SERVER['DOCUMENT_ROOT'] . '/cccitu-waf/cccitu-ban.log'; //被拉黑IP记录文件保存路径
            if (!file_exists($logPath)) {
                @mkdir($_SERVER['DOCUMENT_ROOT'] . '/cccitu-waf/', 0777, true);
                @file_put_contents($logPath, '');
                @file_put_contents($fileht, '');
            }
                $allowtime = 60; //防刷新时间,以秒为单位,具体数字可以根据需要自行调整
                $allownum = 3; //防刷新次数,比如上面设置的房刷新时间为60,这里设置为3,那么60秒访问次数超过3次就会引发警告
                $allowRefresh = 1; //在此警告次数之后拉黑IP,写 1 则是警告一次后,将会拉黑该访问IP地址
                $bantime = 3600; //封禁时间,超时自动解封,以秒为单位,3600 即为 1个小时后解封该IP地址,注意时间最长不能超过30天
                $ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
                $uri = $_SERVER['REQUEST_URI'];
                $cache = new Memcached();
                $cache->addServer('127.0.0.1', '11211') or die('memcached连接失败!');//如果你更改了memcached 默认的IP或端口,请根据实际情况修改
                $inban = $cache->get('cccitu-waf-ban-' . $ip);
            if ($inban) {
                header("HTTP/1.1 403 Forbidden"); //可以自行修改h1和p标签内的提示内容,当被封IP访问此页面时显示。
                exit('<h1>403 Forbidden 非法访问</h1>
                <p>非法访问</p>');
            }
                $wafarr = $cache->get('cccitu-waf-' . $ip);
            if (!$wafarr) {
                $wafarr = [
                    'path' => $uri,
                    'time' => time() + $allowtime,
                    'sum' => 1,
                ];
                $cache->set('cccitu-waf-' . $ip, $wafarr, time() + $allowtime);
            } else {
                if ($wafarr['sum'] > $allownum) {
                    $wafsum_arr = $cache->get('cccitu-waf-sum-' . $ip);
                    if (!$wafsum_arr) {
                        $wafsum_arr = [
                        'sum' => 1,
                        ];
                        $cache->set('cccitu-waf-sum-' . $ip, $wafsum_arr, time() + $bantime);
                    } else {
                        if ($wafsum_arr['sum'] > $allowRefresh) {
                            $cache->set('cccitu-waf-ban-' . $ip, 1, time() + $bantime);
                            file_put_contents($fileht, $ip . "\n", FILE_APPEND);
                        } else {
                            $wafsum_arr['sum']++;
                            $cache->set('cccitu-waf-sum-' . $ip, $wafsum_arr, time() + $bantime);
                        }
                    }
                    file_put_contents($logPath, $ip . '--' . date('Y-m-d H:i:s', time()) . '--' . $uri . "\n", FILE_APPEND);
                    header("HTTP/1.1 403 Forbidden");
                    exit("请求频率QPS超过限制,请酌情访问,多次提醒后会封禁IP!");//可以自行修改提示内容,当访问被警告时,此页面显示。
                } else {
                    $wafarr['sum']++;
                    $cache->set('cccitu-waf-' . $ip, $wafarr, $wafarr['time']);
                }
            }
    }
}

将以上代码,复制到主题 functions.php 最后一行,如果最后一行是 ?>,则要将代码放在 ?> 的上一行。functions.php 文件在哪里?在服务器 /wp-content/themes/ 目录的主题文件夹中。

如果你无法进入服务器,也可以进入:网站后台——外观——主题编辑器——模板函数(functions.php) 进行操作。

第二步:限制具体的网址

  • 专一:限制 wp-login.php 登录注册
  • /**
     * 使用教程:https://www.cccitu.com/5079.html
     * 限制 wp-login.php 的访问频率,可以防止恶意注册和登录暴力破解
     */
    add_action('login_enqueue_scripts', function(){
        cccitu_waf();
    });
    
  • 专一:限制 admin-ajax.php 数据提交
  • /**
     * 使用教程:https://www.cccitu.com/5079.html
     * 限制使用 admin-ajax.php 进行 ajax 异步加载的数据提交的频率,一般文章评论,短信发送等功能都使用了此功能
     * 注意,这里所限制的是通过 post 和 get 提交数据,测试效果时,要以 域名/admin-ajax.php?action=cccitu 的形式访问
     */
    add_action('admin_init', function(){
        if (wp_doing_ajax()){
            cccitu_waf();
        }
    }); 
    
  • 通用:限制 任意一个网址
  • /**
     * 使用教程:https://www.cccitu.com/5079.html
     * 限制任意一个网址
     */
    add_action('init', function(){
        $cccitu_get_url = $_SERVER['REQUEST_URI'];
        $cccitu_waf_check = false;
        //例如要限制 https://www.cccitu.com/5065.html ,就将主域名后面的 /5065.html 填写到代替换的单引号内
        if(strpos($cccitu_get_url, '待替换') !== false) {
            $cccitu_waf_check = true;
            break;
        } 
    
        if ($cccitu_waf_check){
            cccitu_waf();
        }
    }); 
    
  • 通用:限制 任意多个网址
  • /**
     * 使用教程:https://www.cccitu.com/5079.html
     * 限制任意多个网址
     */
    add_action('init', function(){
        //例如要限制 https://www.cccitu.com/5065.html ,就将主域名后面的 /5065.html 填写到代替换的单引号内
        //当三个网址以上时,自己在括号内以英文的逗号,单引号的形式添加即可,比如('/5065.html','admin-ajax.php','wp-login.php')
        $cccitu_waf_kay = array('/5065.html','admin-ajax.php');
        $cccitu_get_url = $_SERVER['REQUEST_URI'];
        $cccitu_waf_check = false;
    
        foreach($cccitu_waf_kay as $word) {
            if(strpos($cccitu_get_url, $word) !== false) {
                $cccitu_waf_check = true;
                break;
            } 
        }
    
        if ($cccitu_waf_check){
            cccitu_waf();
        }
    }); 
    

    为尽量减少影响 WordPress 的性能,虫子菌针对不同的限制需求,写了以上不同的代码,当多个代码都能满足你的需求时,建议优先选择专一的,其次才是通用的。将所选代码同样复制进 functions.php 的最后一行,也就是第一步代码的下面,当第一步和第二步代码都加入后,即可生效。

    相关推荐

    暂无评论