菜单
189-0733-7671

WordPress 登录安全:防爆破、2FA 以及权限收紧

口令复杂度规则为什么是反效果、2FA 怎么配才不会把自己锁在门外、改登录路径会连带影响什么、被撞库之后按什么顺序处置,附 15 项可打勾清单。

曾凤祥
曾凤祥 技术总监
| | | 36 分钟
WordPress 登录安全:防爆破、2FA 以及权限收紧

站点被入侵之后追源头,十次有七次不是「漏洞被利用」,而是有人拿到了一个能用的账号。口令是从别处泄露的、2FA 嫌麻烦没开、外包结束后管理员账号忘了删、离职同事的编辑权限还留着——这些都不需要攻击者有技术,只需要有耐心。

WordPress 安全加固指南的第四节把这件事放在 P0 第二位,给的是判断框架:口令要长、限流有三层、2FA 优先 TOTP、管理员越少越好。这一篇往下走一层,讲具体怎么配、配完会连带影响什么、出事之后按什么顺序处理。

如果你已经怀疑站点被入侵过,先不要在这里花时间——按 WordPress 被黑后怎么清理 走完取证和清理,再回来改账号。后门还在的时候改口令,只是换了一把锁,人还在屋里。

一、三种攻击,防御动作完全不同

「防爆破」是个笼统说法。实际打过来的方式有三种,混在一起谈会导致配了措施却没防住该防的东西。

攻击形态怎么打典型特征对应防御
撞库(凭据填充)拿别处泄露的邮箱+口令组合,批量试几万个站点大量不同用户名、每个只试 1–2 次,单个 IP 失败次数不高口令不复用 + 泄露库自查 + 2FA
定向爆破盯住一个站点,试 admin、站点名、公司名等字典同一 IP 或同一 IP 段高频失败,集中在 wp-login.php限流 + fail2ban + 改登录路径
会话劫持偷 Cookie 或利用 XSS 拿到已登录状态不需要登录成功,直接复用会话HTTPS 强制 + 会话失效 + 前台 XSS 防护

三种里最难防的是撞库。因为它看起来不像攻击:请求频率低、每个账号只错一两次、分散在大量 IP 上,任何按「失败次数」触发的规则都抓不到。唯一的有效防线是「这个口令在别处泄露过所以不能用」和「除了口令还要第二样东西」。

所以在动手之前先想清楚:你要防的是脚本乱扫,还是有人在针对你。前者靠限流和改路径就够;后者只能靠 2FA——这是唯一一个「即使口令泄露也不会立刻失守」的措施。

二、第一步不是加固,是盘点

多数站点从来没数过自己有多少个能登录的账号。先把门数清楚。

# 列出全部用户及其角色
wp user list --fields=ID,user_login,display_name,user_email,roles,user_registered

# 只看管理员
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered

没有 WP-CLI 的话,直接查库:

SELECT u.ID, u.user_login, u.user_email, u.user_registered, m.meta_value AS caps
FROM wp_users u
JOIN wp_usermeta m ON m.user_id = u.ID AND m.meta_key = 'wp_capabilities'
WHERE m.meta_value LIKE '%administrator%';

看四个地方:

  • 不认识的账号。名字像 wordpress、support、test、admin2 的一律警惕。
  • 注册时间。如果一批账号的 user_registered 集中在某个深夜的几分钟内,那基本不是人注册的。
  • 邮箱域名。攻击者常留 @example.com、临时邮箱域名,或者干脆和站点业务不相干的域名。
  • 最后登录时间。WordPress 默认不记录登录时间,装了安全插件才有。没有记录时,用 session_tokens 这个 usermeta 判断——用户登录过就会有这个字段。

隐藏管理员怎么查

攻击者拿到的第一个管理员账号,通常不会老老实实待在用户列表里。有的会改 user_login 让它排在列表末尾不显眼,有的通过 mu-plugin 过滤掉用户列表查询。可靠的判断方式是绕过界面直接比对:

-- 所有在 usermeta 里带 administrator 能力的用户
SELECT user_id, meta_value FROM wp_usermeta
WHERE meta_key = 'wp_capabilities' AND meta_value LIKE '%administrator%';

把这份 ID 列表和后台「用户」页显示的管理员逐个对,对不上的就是被做了手脚的。多站点还要额外查 wp_sitemeta 里的 site_admins,超级管理员的权限不在 wp_capabilities 里。

这一步花不了十分钟,但它是后面所有加固的前提——账号没盘干净,配再多规则也可能留着一个后门钥匙。

三、口令:为什么「强制复杂度」是反效果

很多安全插件提供「强制密码复杂度」:至少 8 位、含大小写、含数字、含符号、每 90 天必须换。这套规则来自 2003 年的 NIST 建议,2017 年就被 NIST 自己废除了(SP 800-63B)。

原因很直接:人面对复杂度规则的行为是可预测的。要求大小写+数字+符号,用户就会写 Company2024!、Password1!、Abc12345!——这些全在世界通用破解字典的前一万条里。要求 90 天换一次,用户就在末尾加数字轮换:Company2024! → Company2025!。

NIST 现在的建议是三条:

  1. 长度优先,最低 8 位,建议 12 位以上,不强制字符种类组合
  2. 比对泄露库,出现在已知泄露数据里的口令直接拒绝
  3. 不做定期强制轮换,只在「疑似泄露」时换

落地怎么做

不用装插件也能做到大半:

  • 管理员和数据库口令用密码管理器生成 20 位以上的随机串,一个站点一个,绝不复用
  • 主机面板(宝塔)、SSH、数据库、WordPress 后台这四个口令互相独立——很多入侵是从面板口令泄露开始的,四处同一个等于一处破全破
  • 泄露库自查:在 haveibeenpwned.com 查管理员邮箱,看是否出现在已知泄露事件里。有的话立刻换口令

改口令的正确方式

不要直接 UPDATE wp_users SET user_pass = MD5('新密码')。WordPress 从 2.5 起就不用 MD5 了,现在(6.8 之后)新口令默认用 bcrypt,旧哈希仍兼容 phpass。手写 MD5 的结果是你把自己锁在门外,而且没有任何报错。

正确做法:

# 用 WP-CLI 改,自动走正确的哈希
wp user update 1 --user_pass='新的长口令'

# 批量把所有管理员的会话踢掉(改完口令必须做)
wp user session destroy $(wp user list --role=administrator --field=ID) --all

如果没有 WP-CLI,写一个一次性脚本走 wp_set_password(),跑完立刻删掉文件。

改口令不会自动踢掉已登录的会话,这一点下面第七节会细说,但它是最容易被忽略的一步:你以为改了口令就安全了,攻击者的 Cookie 还有效。

四、登录入口:改路径值不值得做

「把 /wp-login.php 改成别的地址」是加固清单里的常客。它有用,但用处被高估了。

做法挡得住什么挡不住什么副作用
改登录路径(插件)无脑扫 /wp-login.php 的自动化脚本知道你新路径的定向攻击(路径会出现在页面源码、邮件、浏览器历史里)一串连带故障,见下
限制后台 IP 白名单几乎所有外部登录尝试自己换网络、出差、移动办公一旦 IP 变化就把自己关在外面
关闭 XML-RPCXML-RPC 爆破和应用密码滥用的入口正常表单登录部分 App、Jetpack、旧版发布工具失效
什么都不改,只上 2FA口令泄露后的登录无几乎为零

结论:对批量扫描有效,对定向攻击无效。如果只能做一件事,做 2FA,不要做改路径。

改路径的连带影响清单

这是实际操作里真正费时间的部分。改完之后失效的东西通常不会立刻暴露,而是在几天后某个业务环节出问题:

  • 忘记密码邮件里的重置链接。链接指向的是旧路径,点了 404,用户以为账号废了
  • WP-CLI 和 cron。多数改路径插件会在 CLI 环境下不生效,导致定时任务里的登录相关操作异常
  • 支付回调与第三方通知。部分支付网关、ERP 对接会回调 /wp-admin/admin-ajax.php 或 /wp-json/,如果插件一刀切把 /wp-admin 也改了,回调会 404,表现为「客户付款了但订单没生成」
  • 缓存插件与 CDN 规则。原有的「不缓存 wp-login.php」规则匹配不上新路径,登录页可能被缓存,出现「别人登录后你看到他的后台」
  • 主题自定义登录页。硬编码 /wp-login.php 的模板会失效

如果确实要改,改完按这张清单逐项回归,别只看「能登录了」就算完成。

五、限流:三层怎么分工,别互相抵消

三层的定位不一样,不是「装得越多越安全」。

层拦在哪统计口径适合
Nginx limit_reqPHP 之前请求速率(每秒/每分钟)挡住高频暴力请求,几乎零成本
fail2ban系统层读日志失败次数(按时间窗)挡住持续尝试,封禁时间长
安全插件WordPress 内部失败次数 + 图形验证没有服务器权限时的唯一选择

Nginx:只对登录接口限流

# http {} 块
limit_req_zone $binary_remote_addr zone=wplogin:10m rate=5r/m;

# server {} 块,只对两个入口生效
location = /wp-login.php {
    limit_req zone=wplogin burst=10 nodelay;
    # 原 fastcgi 配置保持不变
}

location = /xmlrpc.php {
    limit_req zone=wplogin burst=5 nodelay;
}

不要把限流加在整个站点上。区块编辑器保存文章时会并发发起几十个请求,burst 设小了会导致编辑页白屏、保存失败——这个坑我们踩过,细节写在WordPress 安全加固指南里,这里不重复。

fail2ban:规则写错会把正常登录算成失败

这是最容易出错的一处。WordPress 登录失败时返回 200(重新渲染表单),成功时返回 302(跳转到后台)。所以最常见的过滤规则——「匹配所有 POST /wp-login.php」——会把你自己每次成功登录也算成一次失败,五次之后把自己封了。

正确的过滤规则只匹配 200:

# /etc/fail2ban/filter.d/wordpress-login.conf
[Definition]
failregex = ^<HOST> .* "POST /wp-login\.php[^"]*" 200
ignoreregex =
# /etc/fail2ban/jail.local
[wordpress-login]
enabled  = true
filter   = wordpress-login
logpath  = /www/wwwlogs/你的域名.log
maxretry = 5
findtime = 600
bantime  = 86400

改之前先 tail -20 看一条真实日志,确认字段顺序和引号形式跟正则对得上——不同 Nginx 日志格式(combined、main、自定义 JSON)差异很大,直接抄别人的正则会静默失效,fail2ban-client status 里显示运行中,但一条都没封过。

把自己封了怎么救

# 看当前封禁名单
fail2ban-client status wordpress-login

# 解封自己的 IP
fail2ban-client set wordpress-login unbanip 你的IP

如果 SSH 也连不上(fail2ban 同时管着 sshd),只能从云厂商控制台的 VNC 登录,或者临时关机挂载磁盘改配置。所以上规则之前先把自己的 IP 加进 ignoreip,这一条比什么都重要。

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 你的固定IP

六、2FA:难的不是开启,是别把自己锁在门外

三种形式的强度差别WordPress 安全加固指南里已经讲过,结论是 TOTP 优先、邮件次之、短信最弱。这里只讲落地时会遇到的六个问题,这些是装完插件之后才会发现的。

一、强制范围给谁。 只强制 administrator 是最小可行方案。编辑、作者这些角色如果共用电脑、多人轮班,强制 2FA 会带来大量「换班登不上」的求助。判断标准是:这个账号能不能装插件、改主题——能,就必须 2FA。

二、备用码必须离线存。 所有 2FA 插件都会生成一批一次性恢复码,多数人点「已保存」就关掉了。正确做法是打印出来或者存进密码管理器,并且不要存在同一台手机上——手机丢了,码也跟着丢。

三、换手机是最高频的事故。 换机、恢复出厂、卸载验证器 App,都会让 TOTP 密钥消失。这时候只剩两条路:用备用码,或者让另一个管理员在后台临时关闭该账号的 2FA。所以站点上永远要保留至少两个管理员账号,其中一个的 2FA 由不同的人持有——只有一个管理员时,丢手机等于丢站点。

四、应用密码可能绕过 2FA。 WordPress 5.6 引入的「应用密码」(Application Passwords)走的是 Basic Auth,不经过登录表单。是否受 2FA 约束取决于插件实现,相当一部分插件不管这条路径。也就是说,开了 2FA 不等于关死了后门——如果不用,直接在 wp-config.php 里关掉:

// 完全禁用应用密码(不需要 REST API 外部调用时)
define( 'WP_ENVIRONMENT_TYPE', 'production' ); // 先确认环境类型
add_filter( 'wp_is_application_passwords_available', '__return_false' );

第二行要放在 mu-plugin 里,不要放主题的 functions.php——换主题就失效了。

五、REST API 和 XML-RPC 的兼容性。 有些 2FA 插件会连带拦截 /wp-json/ 的认证请求,表现是区块编辑器正常但手机 App 登不上、或者第三方发布工具报 401。上线前用编辑器保存一篇草稿验证一遍。

六、插件停更的风险。 2FA 插件一旦停止维护、与新版本 WordPress 不兼容,你会处于「关掉它不安全、留着它登不上」的两难。选插件时优先选装机量大、更新频繁的,并且确认它支持用 WP-CLI 或数据库方式紧急关闭,出问题时至少有退路。

七、会话:登录之后还在发生的事

口令和 2FA 管的是「能不能进来」,会话管的是「进来之后能待多久」。这一层最常被忽略,但在处置入侵时它是关键。

WordPress 登录后会种两个 Cookie:wordpress_[hash](认证信息)和 wordpress_logged_in_[hash](身份标识)。服务端对应的是一份存在 usermeta 的 session_tokens——每次登录生成一个 token,记住登录状态的有效期是 14 天,不勾选是 2 天。

关键点:改口令不会让已登录的会话失效。 攻击者如果已经拿到 Cookie,你改完口令,他那边照样能用。必须显式销毁会话:

# 踢掉某个用户的全部会话
wp user session destroy 1 --all

# 踢掉所有管理员的会话
wp user session destroy $(wp user list --role=administrator --field=ID) --all

# 全局:让所有用户的会话立即失效
wp eval 'wp_destroy_all_sessions();'

如果连 WP-CLI 都用不了,换密钥盐也能达到同样效果——所有 Cookie 的签名失效,等于全体强制重新登录。具体做法和顺序在 wp-config.php 安全配置 里,注意顺序是「先清后门 → 改口令 → 换盐」,反了等于给攻击者发新门票。

另外两个会话相关的设置值得调:

  • 后台会话过期时间:默认 2 天(不勾记住我)对后台偏长,公共电脑场景可以缩短到几小时
  • 并发会话数:WordPress 默认不限制,同一个账号可以在几十个设备上同时在线。对管理员账号,可以考虑限制并发数,异常时能更早发现

八、权限:五个角色各能干什么

WordPress 内置五个角色,能力是包含关系。多数误配来自「不清楚边界,索性都给管理员」。

能力管理员编辑作者投稿者
装插件、换主题✅⛔⛔⛔
改设置、管用户✅⛔⛔⛔
改他人的文章✅✅⛔⛔
发布自己的文章✅✅✅⛔
审核评论✅✅⛔⛔
上传文件✅✅✅✅

投稿者发布的文章需要编辑或管理员审核才能上线;订阅者只能管理自己的资料,不能发文、不能上传文件,所以表里不单列一栏。

三个常见误配:

  • 给内容编辑管理员权限「方便改版式」。管理员能装插件,而插件是 WordPress 最常见的入侵入口。要改版式,用编辑角色 + 主题自带的版式选项,不要给管理员
  • 离职只改口令不删账号。账号还在,只是口令变了——如果这个账号曾经被泄露过,攻击者手上可能还有有效会话。正确做法是删账号,并把其文章转移给新作者
  • 共用一个管理员账号。出问题时无法定位是谁操作的,而且一个人泄露全体沦陷。宁可多建几个账号

自定义角色的坑

需要「只能改某几个栏目」这类细粒度权限时,会用 add_role() 自定义。要注意:add_role() 写进主题的 functions.php 会随换主题失效,而角色数据是存在数据库里的,失效后用户会变成「无角色」,登录后看不到任何菜单,表现为「后台一片空白」。

正确做法是放进 mu-plugin(wp-content/mu-plugins/),它不受主题切换影响:

<?php
// wp-content/mu-plugins/custom-roles.php
add_action( 'init', function () {
    if ( get_role( 'content_manager' ) ) {
        return; // 已存在就不重复创建
    }
    add_role( 'content_manager', '内容管理', [
        'read'         => true,
        'edit_posts'   => true,
        'publish_posts'=> true,
        'upload_files' => true,
        'edit_others_posts' => true,
    ] );
} );

九、外包与交接:账号怎么给,怎么收

给建站公司、运营外包、临时开发开账号,是最容易留下长期口子的一环。原则只有一条:给临时账号,不给主账号;有开始时间,也有结束时间。

场景给什么注意
建站交付期新建管理员,专属该外包方不要把自己账号口令给出去
内容代运营编辑角色不给管理员,装插件需求走你这边
临时排障管理员 + 约定回收日期结束当天删账号,不是改口令
交接给客户客户自己的管理员你的账号降权或删除

交接时按这份清单过一遍:删外包账号 → 改所有共享口令 → 换密钥盐(强制全体重新登录)→ 检查用户列表有无新增 → 查 wp_options 里 active_plugins 有无陌插件 → 看一遍定时任务。

十、异常登录怎么识别,怎么处置

没有安全插件时,判断是否被登录过靠日志和几个痕迹:

迹象在哪里看说明
登录日志里出现没见过的时间点Nginx access log 中 POST /wp-login.php 后跟 302成功登录的标志
session_tokens 有多个陌生条目wp_usermeta 中 session_tokens每个条目对应一次登录
用户列表多出账号后台用户页 + SQL 比对见第二节
文章被改、出现外链文章列表按修改时间排序攻击者常植入外链做 SEO 作弊
定时任务多出陌生项wp cron event list后门常靠 cron 复活

确认被登录过之后,顺序不能乱:

  1. 先取证(日志、用户列表、文件时间),别急着删东西
  2. 再清后门,按 被黑清理手册 走
  3. 然后改口令 + 换密钥盐 + 销毁会话,三件一起做
  4. 最后才加固登录层——在还没清干净的时候加固,等于给入侵者演示你的防御

十一、常见问题

Q:只用一个管理员账号,行不行?

技术上可以,运维上是风险。丢手机、忘记口令、账号被锁,都会导致完全无法进入后台。至少两个管理员,其中一个的 2FA 由不同的人持有。

Q:改登录地址之后,攻击者还能找到吗?

能。新地址会出现在页面源码的登录链接、密码重置邮件、浏览器历史、甚至搜索引擎缓存里。它只挡无脑扫描,不挡定向攻击。

Q:2FA 开了还会被入侵吗?

会。2FA 挡的是「口令泄露后的直接登录」,挡不了插件漏洞、文件上传漏洞、服务器层入侵。它是账号层的最后一道,不是整个站点的最后一道。

Q:多久换一次管理员口令?

不按时间换,按事件换:疑似泄露、人员离职、外包结束、发现异常登录。定期强制轮换会让用户写出可预测的变体,反而更弱。

Q:WordPress 能不能限制登录失败后锁定账号?

能,但要小心。按账号锁定会被用来做拒绝服务——攻击者故意输错你的账号口令,把你锁在外面。优先按 IP 锁定(fail2ban),而不是按账号锁定。

Q:用了 CDN 或反向代理,fail2ban 封的是 CDN 的 IP 怎么办?

需要在 Nginx 里还原真实 IP(real_ip_header X-Forwarded-For + set_real_ip_from CDN 段),否则日志里全是 CDN 节点 IP,一封就是整片用户。配置错了会出现「全站用户突然都访问不了」。

十二、一页纸清单

按顺序做,做完打勾。

#动作优先级怎么验证
1盘点全部用户,列出管理员P0wp user list --role=administrator
2SQL 比对隐藏管理员P0wp_usermeta 中 wp_capabilities 比对
3删除不认识的账号P0用户列表数量下降
4管理员换长口令,不复用P0密码管理器生成
5管理员全部开启 TOTP 2FAP0退出后重新登录需验证码
6备用码离线保存P0两张不同介质各存一份
7至少保留两个管理员账号P0用户列表
8销毁所有旧会话P0wp user session destroy --all
9只对登录接口做 Nginx 限流P1编辑页保存不报错
10fail2ban 规则只匹配 200P1fail2ban-client status 有封禁记录
11ignoreip 加入自己的固定 IPP1连续输错 10 次不被封
12关闭或限制 XML-RPCP1curl -I /xmlrpc.php 返回 403
13禁用应用密码(如不用)P1用户资料页无该区块
14离职/外包账号删除而非改密P1用户列表
15自定义角色代码放 mu-pluginP2切换主题后角色仍存在

十五项里,前八项是 P0,加起来大约一个小时。如果只做三件:删掉多余管理员、开 2FA、销毁旧会话——这三件覆盖了绝大多数「账号被拿走」的场景。

至于账号以外的地方,插件漏洞、文件上传、服务器层,在WordPress 安全加固指南里按优先级排过一遍;插件怎么选型,看 8 款安全插件推荐;连登录地址都找不到的新手,先看 登录网址怎么找。

曾凤祥
曾凤祥 技术总监

在WordPress独立站开发领域深耕逾十年,我始终专注于外贸企业官网搭建与全球化SEO策略落地,积累了丰富而系统的实战经验。多年来,我已累计为数千家企业客户提供定制化建站与增长解决方案,服务对象涵盖制造业、外贸进出口、政府机构等多个行业,兼具技术深度与商业视野,致力于帮助客户在全球市场中实现可持续的线上增长。

不想自己折腾 SEO 和技术细节?

文章能建立行业权威,但要真正带来询盘,背后得有技术架构和 SEO 策略支撑。
把技术交给我们,你只管写好内容。

小兽WordPress团队合影
微信二维码

扫码添加微信

189-0733-7671

点击拨打

联系我们