
只要你的 WordPress 站点暴露在公网,wp-login.php 就几乎一定会被自动化脚本扫描和尝试爆破。这篇文章解决两个最直接的问题:如何把默认登录地址藏起来让扫描脚本扑空,以及如何在服务器层面对登录请求做限速,让爆破工具在几次失败后就被挡住。相比只靠强密码,隐藏入口加限速的组合能把绝大多数低质量攻击流量挡在日常运维视线之外。
先看一个真实场景:一台运行 WordPress 的 [VPS](https://cn.hostease.com/vps/)([虚拟专用服务器](https://cn.hostease.com/vps/)),访问日志里 wp-login.php 的 POST 请求每天有几千次,密码错的、用户名猜的混在一起。这种量级的扫描不会马上得手,但会持续消耗 PHP 进程和数据库连接,拖慢正常访客的加载速度。我们建议的处理顺序是:先隐藏登录入口减少无效请求,再对剩下的真实登录请求做限速兜底。如果你在做整体安全规划,可以先参考 WordPress 安全加固建立全景视角,再回到本文处理登录这一个具体环节。
一、隐藏登录入口:两种主流方式
隐藏 wp-login.php 的思路是让默认地址返回 404 或跳转,只保留你自定义的登录路径。常用实现有两种,选一种即可,不要同时叠加,否则排障时会互相干扰。
第一种是用插件。类似 WPS Hide Login 这样的插件在 WordPress 层拦截登录请求,把 wp-login.php 重定向到自定义地址,后台设置里填一个新路径(例如 /my-secret-login)就能生效。优点是五分钟搞定、不需要碰[服务器配置](https://cn.hostease.com/blog/server/),适合[虚拟主机](https://cn.hostease.com/web-hosting/)或不想改 Nginx/Apache 配置的用户;缺点是插件本身依赖 WordPress 正常加载,如果站点被数据库故障或插件冲突拖垮,登录保护也会跟着失效。另外换主题或迁移站点时要记得先保留该插件的设置,否则自己也会被挡在门外。
第二种是在 Web 服务器层直接拦截。以 Nginx 为例,用 location 匹配 wp-login.php,非白名单来源直接返回 404:
location = /wp-login.php {
allow 203.0.113.10; # 你的固定办公 IP
allow 198.51.100.0/24; # 公司出口网段
deny all;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
这种方式在请求到达 PHP 之前就把非白名单流量拒掉,比插件更省资源,也不依赖 WordPress 本身健康。代价是你需要一个相对固定的访问 IP(或 VPN 出口),IP 经常变的家庭宽带用户会把自己锁在外面。Apache 用户等价写法是用 mod_rewrite 判断 REMOTE_ADDR 后返回 403,思路相同。无论选哪种,改完都要先开一个隐私窗口验证:旧地址应返回 404,新地址能正常登录,再退出当前会话。
二、登录限速:让爆破在几次失败后停下来
隐藏入口解决”看不到”,限速解决”看到了也打不动”。限速的原理是给每个来源 IP 维护一个请求计数窗口,超阈值的登录请求直接返回 429 或 403,爆破工具拿到连续失败后通常会放弃当前批次转向下一个目标。这里给出服务器层的两套配置,都能和上面的隐藏方式叠加使用。
Nginx 用 limit_req 模块实现。先在 http 块定义一个按 IP 的速率区,再在登录 location 里引用:
# http {} 块内
limit_req_zone $binary_remote_addr zone=wplogin:10m rate=5r/m;
# server {} 块内的登录 location
location = /wp-login.php {
limit_req zone=wplogin burst=3 nodelay;
limit_req_status 429;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
rate=5r/m 表示每个 IP 每分钟最多 5 次登录请求,burst=3 允许短暂突发 3 个排队请求。正常用户登录加偶尔输错密码,一分钟内不会超过这个量;爆破脚本每秒几十次的请求会被大量拒绝。如果你已经配置过 Nginx 限流保护整站接口,把登录限速作为其中一条更严格的 zone 即可,两者互不冲突。
Apache 没有 limit_req,等价能力用 mod_evasive 或 mod_security 的 DOS 规则实现。以 mod_evasive 为例:
<IfModule mod_evasive20.c>
DOSPageCount 3
DOSPageInterval 2
DOSSiteCount 30
DOSSiteInterval 5
DOSBlockingPeriod 600
</IfModule>
这组参数的含义是:同一页面 2 秒内被请求超过 3 次、或同站点 5 秒内超过 30 次的 IP,会被封禁 600 秒。对登录页来说这个阈值足够拦住脚本,又不至于影响正常用户。注意 mod_evasive 是全站生效的,如果站点有高频 AJAX 接口,需要用 DOSWhitelist 排除对应路径,避免误伤。


三、三种防护方案怎么选
把上面提到的手段放在一起对比,方便你按自己的环境选择:
- 插件隐藏登录:部署成本最低,五分钟生效,适合虚拟主机用户;依赖 WordPress 自身可用,服务器层不设防。
- Nginx/Apache 白名单:请求未到 PHP 就被拒绝,性能开销几乎为零;要求访问 IP 相对固定,动态 IP 用户需要配合 VPN。
- 服务器层限速:不需要白名单,对任意来源 IP 生效,是兜底手段;阈值要实测调优,设太严会挡住忘记密码的用户。
实际组合建议:虚拟主机用户选插件隐藏 + 强密码 + 双因素;有服务器控制权的用户选白名单或限速至少其一,资源允许时两者都上。从我们处理的站点案例看,只做隐藏不做过限速的站点,扫描流量大约下降七到九成,但精细化的爆破工具仍会探测到新路径;补上限速后,登录接口的无效 POST 基本归零。Hostease 的 [WordPress主机](https://cn.hostease.com/wordpress-hosting/) 默认在服务器层带有基础防护规则,可以覆盖限速这一层,你在应用层再做隐藏入口即可形成双重保护。
如果用 CDN(内容分发网络)代理了站点,注意限速规则要按真实客户端 IP 计数,否则所有请求会共享 CDN 节点 IP 的配额,一个被攻击就全站登录受限。Nginx 上用 real_ip 模块从 X-Forwarded-For 头还原真实 IP 后再进 limit_req_zone,WordPress 侧也要同步设置可信代理,让日志和限速看到同一个 IP。
四、配置后的验证清单
改动生效不代表防护正确,必须实际验证。每次调整后按这个顺序走一遍:
- 隐私窗口访问旧地址 /wp-login.php,预期返回 404 或 403,而不是登录表单。
- 访问新登录地址,正常输入密码登录,确认自己没被限速规则误伤。
- 连续输错密码 5 次以上,预期第 6 次开始返回 429,等一分钟窗口过后再试能恢复。
- 查看访问日志确认拦截记录:
grep "wp-login" /var/log/nginx/access.log | grep 429 | tail,能看到限速触发的痕迹。 - 用手机流量(4G/5G,换一个出口 IP)重复登录测试,确认不同来源 IP 的限速互不影响。
验证时最容易踩的坑是缓存:页面缓存插件或 CDN 可能把 404 页面缓存成登录页(或反过来),导致测试结果失真。验证期间给 wp-login.php 相关路径加 no-cache 头,或者暂时关闭页面缓存再测。

五、总结与下一步建议
WordPress 登录页加固的两条主线是隐藏入口和登录限速:前者让扫描脚本找不到目标,后者让找到目标的请求打不动。插件方式五分钟见效,服务器层方式更彻底,两者叠加是推荐配置。改完配置后必须按清单验证,重点确认自己不会被锁在外面。
总结一下后续可以继续推进的方向:为管理员账号开启双因素认证,即使密码泄露也多一道闸;定期检查 fail2ban-client status 或访问日志里的封禁记录,识别持续攻击源并加入永久黑名单;如果你在选型主机,可以考虑 Hostease WordPress主机这类自带服务器层防护的方案,把限速和拦截交给主机默认规则处理。登录口只是 WordPress 安全的第一扇门,完整的外层防护还可以结合 VPS 入侵应急处理提前准备预案,出事时不慌。