WordPress 登录保护与 XML-RPC 关闭实操:两步堵住爆破入口

如何解决 WordPress 后台频繁被陌生 IP 尝试登录的问题?这篇文章把两件事一次讲清楚:限制登录尝试次数,以及关闭几乎用不到却常被利用的 XML-RPC(WordPress 的远程调用接口)。两者配合,能堵住绝大多数自动化撞库攻击的入口,整个过程不超过半小时。

大多数站长第一次意识到问题,是在访问日志里看到成百上千条指向 wp-login.php 或 xmlrpc.php 的 POST 请求。这些请求来自自动化脚本,它们字典式地试用户名密码,一台服务器每天被动接收上万次尝试并不罕见。单纯改密码解决不了问题,因为脚本会一直试下去;必须让”试错”这件事变得代价高昂。

浏览器窗口登录页上的大挂锁与被封锁的旁门,象征 WordPress 登录保护与关闭 XML-RPC

为什么登录限制和关闭 XML-RPC 要一起做

wp-login.php 是后台登录页,而 xmlrpc.php 是一个老接口,原本用于远程发布、pingback 等功能。它的问题在于:一次请求里可以打包几十组用户名密码(system.multicall),等于把”每分钟试几次”的限制直接绕过了。很多站长装了登录限制插件后仍被爆破,原因就是攻击者换到了 XML-RPC 这条通道。

实际数据上,防护不到位时,一次持续数天的爆破可能有数万次请求,占用 PHP 进程之外还会拖慢正常访客的加载速度。所以正确顺序是:先关掉不需要的 XML-RPC,缩减攻击面;再对登录页做尝试限制,保住必留的入口。

从服务器请求经防护盾校验到封堵入口的三步流程示意

第一步:关闭 XML-RPC

先判断你是否真的在用 XML-RPC:如果你不用 Jetpack 这类依赖远程连接的插件、不用手机 App 远程发文、不做跨站 pingback,那么基本可以确认它对你没有价值,直接关闭即可。

方式一:用代码关闭(无需插件)

在当前主题的 functions.php 末尾,或 Better 一点的方案——建一个站点专属小插件,加入以下两行:

add_filter('xmlrpc_enabled', '__return_false');
add_filter('xmlrpc_methods', '__return_empty_array');

第一行关闭 XML-RPC 引擎本身,第二行清空所有注册的远程方法,双保险。保存后无需重启,立即生效。

方式二:服务器层直接拦截

如果你能操作 Nginx 或 Apache 配置,在站点配置里加一条规则,让 xmlrpc.php 的请求直接返回 403:

location = /xmlrpc.php {
    deny all;
    return 403;
}

Nginx 修改后执行 nginx -t 测试语法,再 systemctl reload nginx 平滑重载。这一层拦截发生在 PHP 之前,连 PHP 进程都不会被消耗,是负载偏高服务器上的首选方案。更多服务器侧的配置经验,可以翻看服务器类教程。

方式三:插件关闭

使用 Disable XML-RPC 之类的插件,装完启用即生效,适合不碰代码的场景。缺点是多一个插件要维护,且部分插件只拦截方法不关闭引擎,启用后务必按下面的方法验证。

验证是否关闭成功:

curl -I https://你的域名/xmlrpc.php

返回 403 或 405 都算关闭成功;如果返回 405 且响应体里出现 “XML-RPC server accepts only POST requests”,说明接口还开着,需要回头检查配置。

左侧敞开被红色箭头涌入的门与右侧被绿色盾牌封闭的门对比

第二步:限制登录尝试次数

XML-RPC 关掉后,剩下的入口就是 wp-login.php。目标是:同一个 IP 连续输错若干次后,暂时禁止它继续尝试。这套思路和安全加固指南里的分层防护是一致的,本文聚焦其中登录入口这一层。

方案 A:插件方式(推荐大多数用户)

常用的 Limit Login Attempts Reloaded 或 Wordfence 都可以。以 Limit Login Attempts Reloaded 为例,启用后进入设置页,推荐配置:

  • 允许重试次数:4 次
  • 锁定时长:20 分钟起,连续多轮锁定后翻倍
  • 开启通知邮件:同一 IP 达到阈值时发信提醒

这个量级对真实用户是安全的——人很少会连错 4 次密码,而脚本会被反复锁定直至放弃。如果想进一步收紧入口,还可以参考修改后台登录地址相关教程,把默认登录路径一并换掉。

方案 B:代码方式(无插件)

把下面这段放进主题 functions.php,利用瞬态(transient,WordPress 的临时存储机制)记录失败次数:

add_action('wp_login_failed', function($username) {
    $ip  = $_SERVER['REMOTE_ADDR'] ?? '';
    $key = 'll_' . md5($ip);
    $tries = (int) get_transient($key);
    $tries++;
    if ($tries >= 5) {
        set_transient($key, $tries, 30 * MINUTE_IN_SECONDS);
        wp_safe_redirect(home_url('/?login_blocked=1'));
        exit;
    }
    set_transient($key, $tries, 30 * MINUTE_IN_SECONDS);
});

30 分钟内同一 IP 累计失败 5 次就跳转到拦截页。注意这段依赖 REMOTE_ADDR,如果你的站点前面有 CDN 或反向代理,需要先确认日志里的 IP 是真实访客 IP,否则会误伤所有共用出口 IP 的用户。

服务器层限速(有条件时再加一层)

Nginx 可以对登录页按 IP 限速,例如每秒最多 1 个请求、超出返回 429。虚拟主机用户拿不到服务器配置权限,用方案 A 就够了;使用 VPS(虚拟专用服务器)的用户可以两层都上,效果更稳。如果站点前面挂了 CDN(内容分发网络),限速规则要按真实访客 IP 生效,否则会误伤共用出口 IP 的用户。

常见坑与排查

改完之后自己也登不进去了。 多半是锁定阈值设得太低(2 次以下)或 IP 判断错误(CDN 场景下所有访客被当成同一个 IP)。检查插件的锁定日志,或把代码方案里的次数放宽到 5 次,并确认 REMOTE_ADDR 是否经过了代理转发头处理。

关闭 XML-RPC 后某插件失灵。 Jetpack、部分移动端发布 App、某些备份插件的远程推送依赖 XML-RPC。逐一确认插件列表,确实需要的就保留接口,但至少关闭其中的密码认证方法,并配合登录限制兜底。

验证总清单:

  1. curl -I https://你的域名/xmlrpc.php 返回 403/405
  2. 故意输错密码 5 次,确认第 5 次后 IP 被锁定
  3. 等待锁定时间过后,确认自己能正常登录
  4. 查看访问日志,wp-login.php 和 xmlrpc.php 的异常 POST 是否明显减少

防护之外:别忘了这些配套动作

登录保护是第一道门,配合下面几件事效果才完整:

  • 管理员账号不要用 admin 这种用户名,攻击字典里它是必试的第一项
  • 启用强密码策略,有条件时对管理员加两步验证
  • 定期更新 WordPress 核心、主题和插件,旧版本漏洞同样会被自动化脚本利用
  • 如果站点存了客户资料或承载业务订单,建议把数据库备份频率提到每日一次,出现问题可以完整回滚

如果你需要一个从登录防护到数据备份都省心的运行环境,Hostease 的虚拟主机默认集成防火墙与每日备份,管理面板里可以直接管理安全设置;需要更多控制权的话,VPS 主机允许你在服务器层自定义拦截规则。

总结一下:XML-RPC 对多数站点是纯负担,先关掉它缩减攻击面;再对 wp-login.php 做尝试限制,锁定连续失败的 IP;最后用强用户名、强密码和更新习惯补齐基础盘。这四步都做完,自动化爆破对你站点的威胁就基本被压制住了。建议今天就检查一遍你的 xmlrpc.php 状态——花五分钟 curl 一下,可能省掉未来一次安全事件。

发表评论