微信扫码,获取更多

防止黑客利用xmlrpc.php接口分布式暴力破解WordPress网站

通过之前的操作,我已经搭建好了wordpress个人网站,但没过多久,就收到了服务器提供商告警:CPU资源占用过高。通过日志排查(进入“my_website”文件夹后,输入命令:docker logs wordpress_nginx 2>&1 | tail -n 500),锁定为:黑客暴力攻击式刷 xmlrpc.php 接口(日志中能看到很多个ip,不停的重复 POST,类似这样:POST //xmlrpc.php HTTP/1.1...)。

经查询,xmlrpc.php是 WordPress 提供的一个早期 API 接口,用于允许远程发布(例如通过手机App发文章),黑客利用这个接口,通过一次 POST 请求就可以尝试成百上千个用户名和密码的组合,这比攻击登录页面 wp-login.php 效率高得多。

我的网站虽然设置了每秒10个请求的限制,但攻击者用更低的频率攻击,且采用大量ip分布式攻击的方式,并掌握了管理员用户名(通过访问 https://anjir.top/?author=1获取),理论上,只要时间充足,密码一定会被攻破。又因为网站设置主要缓存静态资源,不缓存动态请求,每一次 POST 请求,Nginx 都会把它转发给后面的 WordPress (PHP-FPM) 处理。WordPress 需要连接数据库、验证信息,这个过程会消耗大量的 CPU 和内存,所以导致CPU资源占用过高告警。

要解决这个问题,其实有个很简单的解决方案:直接在 Nginx 层拒绝任何对xmlrpc.php这个文件的访问,然后只通过WordPress后台发布文章就行了。但我个人还是有用到xmlrpc接口的场景,所以不能完全封堵了。通过咨询AI,我找到了“Nginx + Fail2ban”方案,完美解决了现阶段的需求。本篇文章主要记录:使用“Nginx + Fail2ban”方案,解决黑客利用xmlrpc.php接口、wp-login.php页面暴力破解WordPress网站的问题。

简单5个步骤

  1. 启用并配置防火墙 UFW
  2. 修改 Nginx 配置,记录更详细的日志
  3. 配置 Fail2ban
  4. 设置白名单并重启 Fail2ban
  5. 检查封禁效果

第一步:启用并配置防火墙 UFW

  1. 安装:

    apt update && apt install ufw
  2. 设置默认规则:

    ufw default deny incoming
    ufw default allow outgoing
  3. 开放必要端口:

    ufw allow ssh
    ufw allow http
    ufw allow https
  4. 启用 (请确保已放行SSH):

    ufw enable
  5. 检查状态:

    ufw status

第二步:修改 Nginx 配置,记录更详细的日志

为了让 Fail2ban 能更好地工作,我们需要让 Nginx 在日志中记录 POST请求的具体内容。这会稍微增加日志文件的大小,但对于安全来说是值得的。

  1. 修改 Nginx 主配置文件 nginx.conf

    我们需要修改 Nginx 的主配置文件,而不是我们站点的 app.conf。由于我们在 Docker 中运行,这个文件在容器内部。最简单的办法是把它复制出来,修改,然后通过卷映射挂载回去。

    从容器中复制 nginx.conf到宿主机

    cd ~/my_website
    # 为主配置文件创建一个目录
    mkdir -p ./nginx/main-conf
    # 从正在运行的 nginx 容器中复制文件
    docker cp wordpress_nginx:/etc/nginx/nginx.conf ./nginx/main-conf/nginx.conf

    编辑复制出来的 nginx.conf

    nano ./nginx/main-conf/nginx.conf

    找到 log_format main,修改为(即末尾添加 $request_body变量,让它记录 POST 的内容):

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" "$request_body"';
  2. 修改 docker-compose.yml 挂载配置

    在 my_website 目录下创建日志文件夹:

    mkdir -p ./nginx/logs

    修改 docker-compose.yml,为 nginx 服务添加日志卷映射,和挂载我们修改后的 nginx.conf

    nano docker-compose.yml

    在 nginx 服务的 volumes 部分,新增两行:

    volumes:
    -./nginx/main-conf/nginx.conf:/etc/nginx/nginx.conf:ro# <--- 新增
    -./nginx/logs:/var/log/nginx# <--- 新增
    -./nginx/conf.d:/etc/nginx/conf.d
  3. 切换网络模式为 host
    (删除 ports,添加 network_mode)

    我们让 Nginx 容器直接使用宿主机的网络。这样,Nginx 就能直接看到来自外部的、未经 Docker NAT 转换的原始请求,从而获取到真实的客户端公网 IP。

    继续对docker-compose.yml中的 nginx 服务进行如下修改: a. 删除 ports 部分:在 host 模式下,容器直接监听宿主机的端口,不再需要端口映射。 b. 添加 network_mode: "host"。 c. 修改 wordpress 的连接方式:由于 Nginx 现在和宿主机在同一个网络命名空间,它不能再通过服务名 wordpress 来连接了。它需要通过宿主机的 localhost (127.0.0.1) 和 WordPress 容器映射出来的端口来连接。所以我们也要修改 wordpress 服务。

    请将 docker-compose.yml 文件中的 nginx 和 wordpress 服务部分,修改为以下内容:

    wordpress:
    image:wordpress:php8.2-fpm
    container_name:wordpress_fpm
    restart:always
    # 新增 ports 映射,让 fpm 的 9000 端口暴露给宿主机
    ports:
    -"127.0.0.1:9000:9000"
    depends_on:
    -db
    volumes:
    -./wordpress/html:/var/www/html
    environment:
    WORDPRESS_DB_HOST:db:3306
    WORDPRESS_DB_USER:'wordpress_user'
    WORDPRESS_DB_PASSWORD:'YOUR_STRONG_USER_PASSWORD'
    WORDPRESS_DB_NAME:'wordpress'
    # wordpress 仍然在 app-network 中,以便连接 db
    networks:
    -app-network

    nginx:
    image:nginx:1.27.0-alpine
    container_name:wordpress_nginx
    restart:always
    # 关键修改:使用 host 网络模式
    network_mode:"host"
    # 不再需要 ports 映射
    # ports:
    #   - "80:80"
    #   - "443:443"
    volumes:
    -./nginx/main-conf/nginx.conf:/etc/nginx/nginx.conf:ro
    -./nginx/logs:/var/log/nginx
    -./nginx/conf.d:/etc/nginx/conf.d
    -./nginx/cache:/var/cache/nginx
    -./wordpress/html:/var/www/html:ro
    -./certbot/conf:/etc/letsencrypt
    -./certbot/www:/var/www/certbot
    # 在 host 模式下,nginx 不再属于 app-network
    # networks:
    #   - app-network
  4. 修改 Nginx 站点配置文件 app.conf

    由于 Nginx 现在需要通过 localhost 来连接 WordPress,我们需要修改 PHP-FPM 的转发地址。

    nano ./nginx/conf.d/app.conf

    找到 location ~ .php$ { ... } 块,将 fastcgi_pass wordpress:9000; 修改为 fastcgi_pass 127.0.0.1:9000;

    location ~ .php$ {
        # ... (其他配置) ...
        # 连接到宿主机的 9000 端口,该端口已映射到 WordPress 容器
        fastcgi_pass 127.0.0.1:9000;
        # ... (其他配置) ...
    }
  5. 重启

    docker compose down
    docker compose up -d

第三步:配置 Fail2ban

  1. 安装:

    apt install fail2ban -y
  2. 创建 jail 配置:

    nano /etc/fail2ban/jail.d/wordpress-zerotolerance.conf

    将以下定制好的内容粘贴进去:

    [wordpress-xmlrpc]
    enabled  = true
    port     = http,https
    filter   = wordpress-xmlrpc
    logpath  = /root/my_website/nginx/logs/access.log
    # 任何一次匹配都立即触发
    maxretry = 1
    # 封禁时间为30天
    bantime  = 30d
    # findtime 在 maxretry=1 时意义不大,但最好保留
    findtime = 1m

    [wordpress-login]
    enabled  = true
    port     = http,https
    filter   = wordpress-login
    logpath  = /root/my_website/nginx/logs/access.log
    # 任何一次匹配都立即触发
    maxretry = 1
    # 封禁时间为1天
    bantime  = 1d
    findtime = 1m
  3. 创建对应的 filter (过滤器) 文件

    为 xmlrpc.php 创建 filter

    nano /etc/fail2ban/filter.d/wordpress-xmlrpc.conf

    粘贴以下内容:

    [Definition]
    failregex = ^<HOST> - .* "POST /+xmlrpc.php HTTP/.*
    ignoreregex =

    以及为 wp-login.php 创建 filter

    nano /etc/fail2ban/filter.d/wordpress-login.conf

    粘贴以下内容:

    [Definition]
    failregex = ^<HOST> - .* "POST /+wp-login.php.*
    ignoreregex =

第四步:设置白名单并重启 Fail2ban

这一步至关重要,防止你被自己锁在外面。

  1. 编辑 jail.local 添加你自己的 IP

    nano /etc/fail2ban/jail.local

    找到或添加 ignoreip 这一行,并加上你自己的本机 IP段(百度“ip”,家用宽带动态ip前3段一般不变,最后一段全包含即可,比如百度查询到你此时的ip是:117.100.100.100,那么加白的ip段可以填:117.100.100.0/24)。

    [DEFAULT]
    ignoreip = 127.0.0.1/8 ::1117.100.100.0/24
  2. 重启 Fail2ban 使所有配置生效

    systemctl restart fail2ban
  3. 检查 Fail2ban 状态

    fail2ban-client status

    你应该能看到 Jail list: 下面有 wordpress-login 和 wordpress-xmlrpc 这两个活动的 jail。


第五步:检查封禁效果

wp-login.php封禁验证:
a. 进行测试:

  • 用你的手机网络(不要用常用 Wi-Fi)访问 https://anjir.top/wp-login.php。

  • 只输入一次错误的密码。

  • 然后尝试刷新页面或再次访问。你应该会发现网站已经无法访问了。

  • 回到服务器,执行 fail2ban-client status wordpress-login,你会看到你手机的 IP 已经被列入了封禁列表。

b. 练习解封:
既然测试成功了,就练习一下解封自己的手机IP吧。

  • 1
  • 2
# 假设你手机IP是 222.222.222.222
fail2ban-client unban 222.222.222.222

xmlrpc.php封禁验证:

打开2个SSH 终端连接服务器窗口,一个用来操作登录,另一个用来看日志。

  1. 监控日志:

    tail -f /root/my_website/nginx/logs/access.log

  • 等待新的攻击日志出现。当下一条类似 5.101.157.127 ... "POST /xmlrpc.php ..." 的日志出现时,Fail2ban 就会立刻匹配到它。

  • 检查 Fail2ban 状态:
     稍等片刻后,再次执行:

    fail2ban-client status wordpress-xmlrpc

    这一次,你应该会看到 Currently failed 和 Total failed 的计数增加了,并且 Banned IP list 中出现了新的被封禁的 IP。


    未经允许不得转载:无花果 » 防止黑客利用xmlrpc.php接口分布式暴力破解WordPress网站

    觉得文章有用就打赏一下文章作者

    支付宝扫一扫打赏

    微信扫一扫打赏