WordPress 登录被爆破:关掉这两扇门
2026年10月9日 · 技术
你是否遇到过这种情况:WordPress 后台的「登录失败尝试」通知邮件一封接一封,登录防护插件面板里的失败计数只增不减。这种情况是你的站被机器人暴力破解了(brute force,行话叫「爆破」),机器拿着用户名字典和密码字典,一遍遍去撞后台登录口。
对付它只需要两处改动,把登录页从默认地址挪走,再把备用入口 xmlrpc.php 在网关层封死。这篇文章会把判断过程、操作步骤、验证清单和容易踩的坑都讲清楚。
速览:
- 先看日志判断攻击性质:同一 /24 网段轮换 IP、每个 IP 只试一两次、用户名全是 admin 这类字典词,就是全网撒网,不是针对性攻击
- 撒网机器人几乎只打默认的 /wp-login.php,把登录地址改掉是性价比最高的一刀
- 封 xmlrpc.php 要在网关层 403,让请求进不了 PHP;改完配置必须 restart 而不是 reload
先读懂攻击,再决定怎么防
动手前先看日志。登录防护插件(Limit Login Attempts Security,官方页面自称服务着 200 万个 WordPress 网站)的面板把线索摆得很清楚:失败次数、来源 IP、被试的用户名。
三个特征叠在一起,攻击的性质就定了。IP 在同一个 /24 网段里轮换,每个 IP 只打一两次;被试的用户名全是通用字典:admin、Admin、admin@wordpress.com;没有针对站点内容的探测痕迹。这不是有人盯上了你,是僵尸网络的代理池在全互联网撒网,你的站只是名单里的一行。
这个判断决定后面所有取舍。针对性攻击要按针对性防御来打;撒网攻击只要让脚本「不划算」就够了。扫一圈打不开你的门,机器人就去找下一家,没有动机死磕。
看日志时还有一件事比加固更早,就是先确认防线有没有被突破。锁定计数稳定增长,说明现有防线每一发都拦住了,站点没有被攻破,前台不受影响。先把这句跟团队说清楚,别带着「是不是被黑了」的恐慌乱动手。
选型:改登录地址是对撒网攻击的第一刀
WordPress 默认对登录失败次数没有上限1,爆破的成本因此极低。而撒网机器人几乎只打默认的 /wp-login.php。改掉地址,等于把店门从步行街挪进小巷,绝大多数过路机器人根本走不到门口。这就是整套加固的第一刀,也是性价比最高的一刀。
藏起 WordPress 登录页:装上插件只算做了一半
改登录地址可以用 WPS Hide Login,很轻的一个插件,不改核心文件、不加伪静态规则,纯粹靠拦截请求改道2,关掉插件站点就回到原样。
第一个坑是插件激活后如果什么都不设置,登录页会落到一个弱默认地址「login」,而 login 恰好就在机器人的字典里。装完必须显式把地址改成自己的:
wp option update whl_page <你的新地址>
wp rewrite flush
第二行不是多余的。用 WP-CLI 写配置不会触发插件自带的伪静态刷新,不手动 flush,新地址可能不生效,又一个「装上了但没起作用」的暗坑。
新地址的选取有三条原则:要手输,得好记;跟品牌相关但别太直白,品牌词的组合不在机器人字典里;避开 WordPress 的保留参数(feed、author 这类,插件会拒收)。
改完用四条验证收口:
| 请求 | 期望结果 |
|---|---|
| /wp-login.php | 404 |
| /<新地址>/ | 200,登录表单正常渲染 |
| /wp-admin/(未登录) | 302 跳向 404 页,伪装成死路 |
| 调试日志 | 无新增 PHP 报错 |
封掉第二扇门:xmlrpc.php
登录页藏好了,机器人还剩一条路,就是 xmlrpc.php。XML-RPC 是 WordPress 的传统远程接口,覆盖发文章、传媒体、查用户等操作3。它接受「用户名+密码」式调用,等于一个没跟着换地址的第二登录口。藏门之后,爆破流量会自然流向它。
如果站点不用远程发布,也不开 pingback,这个接口就没有存在的必要,可以在网关层(以 Caddy 为例)直接拒绝,请求根本不进 PHP:
handle /xmlrpc.php {
respond 403
}
三行配置背后有两个真实的坑。
坑一在校验。改动上生产前,用与生产同版本的容器镜像跑配置校验,可能报「server block without any key is global configuration」(站点块没有键,成了全局配置)。配置本身没写错。配置里的站点地址如果是环境变量占位符,校验容器没注入变量,占位符展开成空,就会误报成语法问题。教训是要让校验环境和运行环境的变量对齐,否则报的错误和真正的病灶毫无关系。
坑二在生效。配置文件如果是挂载进容器的单文件,版本库更新换文件后,容器里钉住的还是旧文件的 inode,reload 读到的仍旧是旧配置,看似成功实则没生效。这种挂载方式下改配置,一律 restart 而不是 reload,代价是中断几秒。
复验时 GET、POST 各来一次。POST 才是机器人真正调用的方法,只验 GET 等于只锁了展览用的那扇门。两者都 403、前台页面 200,这一步才算完。日后若要用手机 App 或 Jetpack 远程发布,删掉这三行、重启即恢复。
上生产:备份、验证矩阵和书签
生产动手前先备份整库。这类改动理论上可回滚,但「理论上」三个字不配出现在生产操作里。
部署时有个值得记的小决策。插件文件如果随版本库就位,生产上用激活(activate)就够了,不必安装(install),因为 activate 只写数据库,不受「禁止后台改文件」的服务器锁影响,也省掉生产服务器从 wordpress.org 下载,国内机器连官方源并不总是顺畅。
上线后把整套验证矩阵在生产重跑一遍:旧地址 404、新地址 200、未登录访问后台被引向 404、xmlrpc 双 403、首页与主要内页 200、登录页无缓存头。全过,前台零影响。
然后是最容易被工程视角漏掉的一步,把新登录地址交给每一个要登录后台的人,看着(或至少确认)他们存进书签。旧地址已经 404,拿着旧书签访问,看到的只是一个打不开的页面。对不明就里的人来说,这和「网站挂了」没有任何区别。
结果与可带走的清单
加固后的回看:
| 检查项 | 加固前 | 加固后 |
|---|---|---|
| /wp-login.php | 200,登录表单照常渲染 | 404 |
| 新登录地址 | 不存在 | 200,正常登录 |
| /xmlrpc.php(POST) | 200,接口可达 | 403 |
| 登录失败记录 | 持续增长 | 曲线掉下去 |
给正在管 WordPress 站的你,按性价比排序:
- 先看日志再动手,网段轮换加字典用户名就是撒网,撒网的解法是让脚本不划算,不是堆设备
- 改登录地址是第一刀,注意插件的弱默认值「login」,装完必须显式设置并手动刷新伪静态
- xmlrpc.php 用不用决定封不封,不用远程发布和 pingback 就在网关 403,要用时删三行即恢复
- 改完逐项验证,404/200/403 每项都实际请求到位,GET 和 POST 都要验
- 把新地址的送达当成交接物,旧地址变 404 的那一刻起,新地址没交到每个要登录后台的人手上,任务就没结束
这类加固不需要引入任何新的安全产品,工夫应该花在读日志、做验证和交接上。安全加固的性价比从来不在「买什么」,在「看懂了什么」:门藏在哪、机器人从哪来、每一层防线怎么证明自己活着。想清楚这三件事,两处改动就够了。