WordPress 安全加固完整清单:从第一天就做对的每一步
最后更新:2026-05-09
绝大多数 WordPress 被黑的事件有一个共同特征:不是因为黑客技术高超,而是因为站长少做了几件很简单的事。 默认表前缀、未禁用的 XML-RPC、暴露的版本号、从来不更新——这些小疏漏合在一起,就变成了一扇扇门。
安全加固不是出事后才考虑的,而是从安装 WordPress 那一刻就该做对的事。这篇文章整理了一份完整的加固清单,从安装时的安全配置到运行中的持续加固,再到万一被黑之后的恢复流程。你可以直接把它当成标准操作手册,逐项核对执行。
一、安装时的安全配置
两个在安装 WordPress 时就能(也必须)做的事。如果你用的是主机一键安装,这些设置多数会在安装向导中出现,注意别一路点"下一步"跳过。
🏷️ 修改数据库表前缀
WordPress 默认表前缀是 wp_。全球几亿个 WordPress 网站中,至少一半用的是这个默认值。这意味着黑客写的自动化攻击脚本,SQL 注入 payload 里硬编码的就是 wp_users、wp_options。
// 在 wp-config.php 中,安装前修改这行:
$table_prefix = 'wp_'; // 默认的,不安全
// 改成随机字符串:
$table_prefix = 'bk8x2_'; // 用大小写字母+数字的随机组合,6-10位
对于已建好的站:改表前缀需要执行 SQL,不是简单改一行 PHP。用 Brozzme DB Prefix 插件或在 phpMyAdmin 中手动执行以下操作:
-- 1. 列出所有需要重命名的表
RENAME TABLE wp_commentmeta TO newprefix_commentmeta;
RENAME TABLE wp_comments TO newprefix_comments;
RENAME TABLE wp_links TO newprefix_links;
RENAME TABLE wp_options TO newprefix_options;
RENAME TABLE wp_postmeta TO newprefix_postmeta;
RENAME TABLE wp_posts TO newprefix_posts;
RENAME TABLE wp_terms TO newprefix_terms;
RENAME TABLE wp_termmeta TO newprefix_termmeta;
RENAME TABLE wp_term_relationships TO newprefix_term_relationships;
RENAME TABLE wp_term_taxonomy TO newprefix_term_taxonomy;
RENAME TABLE wp_usermeta TO newprefix_usermeta;
RENAME TABLE wp_users TO newprefix_users;
-- 2. 更新 wp_options 和 wp_usermeta 中引用旧前缀的值
UPDATE newprefix_options
SET option_name = REPLACE(option_name, 'wp_', 'newprefix_')
WHERE option_name LIKE 'wp_%';
UPDATE newprefix_usermeta
SET meta_key = REPLACE(meta_key, 'wp_', 'newprefix_')
WHERE meta_key LIKE 'wp_%';
⚠️ 改表前缀操作前必须先完整备份数据库。改完后立即测试登录、浏览页面、后台操作是否正常。
🔑 更换密钥盐(Authentication Keys & Salts)
wp-config.php 里有 8 行 AUTH_KEY 等常量,这些密钥用于加密用户的登录 Cookie 和密码 hash。WordPress 安装时自动生成,但如果你是用一键安装工具或者从别人那里接手了一个旧站——立刻更换。
访问 WordPress.org Secret Key Generator ,每次刷新页面都会生成一组全新的密钥。复制全部 8 行,替换掉 wp-config.php 中对应的旧值:
define('AUTH_KEY', 'F]9Oq}>4|o+~p32J1nX&Z]@K.$l6$B@CbKn-0H`5N;S_f@/M6#<d_/E+,:T`lCoo');
define('SECURE_AUTH_KEY', '!PNb7C+:mh,?[%p3%8-IE~Zb|R3+P&eqPohB{9@_mWf~{*I~SvB]X`g;+81S}~lV');
define('LOGGED_IN_KEY', ';7n6f,>]hH,|p$2U_g~j<Y /dW*LbgEd?gs)3k|sz:=[`J1iPp9gyiY72XpXm!dW');
define('NONCE_KEY', 'OdchLw|=:t5X+J+]},V7h;-!D;`Z-|?q6~^YJ[?IqhH-MrR6]`X&KbM;ycYc*2w[');
define('AUTH_SALT', '5+=,J_UPUaVp4o$/,O9#vT*kA<-]o+UzK[8%p-d?ry}irHmR`^W4w#5&Nf`}(Tbi');
define('SECURE_AUTH_SALT', ';jrq9e6]ri1,~-{GrM_VO:MQK*sBq|PJksmzP7<}~=P@cE1?n;3c;@U0$T|VyN;T');
define('LOGGED_IN_SALT', 'ytJx=@sK;gN^S?M?2c}f,JsU|,Fec[?I}V.x:,ri!IpibU%q*[{ps:N;*uU#(zqU');
define('NONCE_SALT', '?;Kf_&a6v+8(^?I8A6Pk=R3#z,-g1{3IsT9D4;eSg#N]6B|vo2K*O5dA|?V!pjX');
更换密钥盐后,所有用户的登录状态都会失效,需要重新登录。这是故意为之——如果攻击者持有旧的登录 Cookie,密钥旋转后立即失效。
🔐 安全地设置文件权限
# 推荐的文件系统权限设置(通过 SSH 执行)
# 目录 755:所有者可读写执行,其他人只读执行
find /www/wwwroot/你的网站目录/ -type d -exec chmod 755 {} \;
# 文件 644:所有者可读写,其他人只读
find /www/wwwroot/你的网站目录/ -type f -exec chmod 644 {} \;
# wp-config.php 特殊保护:400(只读)或 440
chmod 400 /www/wwwroot/你的网站目录/wp-config.php
# .htaccess 同样加保护
chmod 444 /www/wwwroot/你的网站目录/.htaccess
wp-config.php 包含数据库密码,权限降到 400 是最低限度。

二、运行中的持续加固
安装时做的设置是地基,运行期间要持续加固防御层。以下操作按影响面从小到大排列——建议从头到尾逐个执行。
🚫 禁用 XML-RPC
XML-RPC 是 WordPress 里最臭名昭著的攻击入口之一。它是一个旧的远程发布接口,现在除了通过 WordPress App 发文章和管理 Jetpack 插件之外几乎没有正常用途。
// 在主题 functions.php 中彻底禁用 XML-RPC
add_filter('xmlrpc_enabled', '__return_false');
// 同时移除 HTTP 头部中的 XML-RPC 链接
remove_action('wp_head', 'rsd_link');
remove_action('wp_head', 'wlwmanifest_link');
如果你用了 Jetpack 插件,Jetpack 依赖 XML-RPC 进行通信,不能直接禁用。替代方案是用 Nginx 防护层限制访问频率:
# 在 Nginx 配置中限制 xmlrpc.php 的请求速率
location = /xmlrpc.php {
limit_req zone=wp_xmlrpc burst=2 nodelay;
deny all; # 或者直接 deny all 后只 allow Jetpack IP
}
👻 隐藏 WordPress 版本号
WordPress 默认在以下位置暴露版本号,方便自动化扫描器识别:
// 在主题 functions.php 中移除版本号
remove_action('wp_head', 'wp_generator'); // meta 标签
add_filter('the_generator', '__return_empty_string'); // RSS feed
// 同时阻止版本号通过脚本和样式链接的查询参数暴露
function remove_wp_version_strings($src) {
if (strpos($src, 'ver=') !== false) {
$src = remove_query_arg('ver', $src);
}
return $src;
}
add_filter('script_loader_src', 'remove_wp_version_strings', 15);
add_filter('style_loader_src', 'remove_wp_version_strings', 15);
执行之后,检查 /wp-content/plugins/ 和 /wp-content/themes/ 下的 readme.txt 文件——这些文件常常暴露插件和主题的版本号。用 Nginx 规则阻止直接访问:
# 阻止访问 readme.txt 和 readme.html
location ~* /(readme\.(txt|html)|changelog\.(txt|md)|license\.txt) {
deny all;
}
🔒 限制 REST API
WordPress REST API 在 4.7 版本后默认开启,未登录状态下可以查询用户列表、文章列表等信息。攻击者通过 /wp-json/wp/v2/users 可以获取全站用户名列表——这就相当于拿到了登录暴力破解的用户名字典。
// 在主题 functions.php 中:
// 对未登录用户禁用 REST API 的用户端点
add_filter('rest_endpoints', function($endpoints) {
if (!is_user_logged_in()) {
// 移除用户端点
if (isset($endpoints['/wp/v2/users'])) {
unset($endpoints['/wp/v2/users']);
}
if (isset($endpoints['/wp/v2/users/(?P<id>[\d]+)'])) {
unset($endpoints['/wp/v2/users/(?P<id>[\d]+)']);
}
}
return $endpoints;
});
// 或者更激进:未登录状态下完全禁用 REST API
add_filter('rest_authentication_errors', function($result) {
if (!empty($result)) {
return $result;
}
if (!is_user_logged_in()) {
return new WP_Error('rest_not_logged_in', '请登录后使用 API', ['status' => 401]);
}
return $result;
});
⚠️ 完全禁用 REST API 会影响 Block Editor(Gutenberg)和一些前端交互功能。如果你不确定影响范围,只禁用用户端点就够了。
🚫 禁用后台文件编辑
WordPress 后台自带了主题和插件的在线编辑器(theme-editor.php 和 plugin-editor.php)。这个功能对黑客来说是个礼物:一旦获取了管理员权限,不需要 FTP/SSH 就能直接编辑 PHP 文件,写入后门。
// 在 wp-config.php 中禁用文件编辑(最简单也最重要的一行)
define('DISALLOW_FILE_EDIT', true);
同时禁止在后台安装插件和主题(如果团队不需要自行安装):
define('DISALLOW_FILE_MODS', true);
如果你停用了 DISALLOW_FILE_MODS,你的 WordPress 后台将无法安装/更新/删除任何插件和主题——你需要通过 WP CLI 或手动 FTP 来管理。对于托管维护站点(客户的站、公司官网),这是最强有力的保护。
🛡️ 强化登录安全
除了 2FA(已在上一篇 #43 中详细展开),这里还有几个登录层面的加固措施:
// 限制登录尝试次数(配合 Limit Login Attempts Reloaded 插件更完善,但纯代码也行)
// 1. 隐藏登录错误的具体原因(不让攻击者知道"用户名不存在"还是"密码错误")
add_filter('login_errors', function() {
return '登录信息不正确,请重试。';
});
// 2. 禁用用户名枚举(通过 ?author=1 查询参数)
add_action('template_redirect', function() {
if (is_author() && !is_user_logged_in()) {
wp_redirect(home_url(), 301);
exit;
}
});
🚫 阻止目录浏览
如果服务器启用了目录索引(Indexes),访问 /wp-content/uploads/2026/ 会列出目录下所有文件,攻击者可以直接遍历你的资源文件。
# 在 .htaccess 或 Apache 配置中
Options -Indexes
# 在 Nginx 配置中(默认已禁用,检查确认)
autoindex off;
🔄 阻止 PHP 在 Uploads 目录执行
这是文件上传攻击的最后一道防火墙。即使攻击者绕过了 WordPress 的文件类型检查上传了一个伪装成图片的 PHP 文件,以下规则能阻止它被执行:
# 在 Nginx 配置中,uploads 目录下禁止执行 PHP
location ~* /wp-content/uploads/.*\.php$ {
deny all;
}
# 在 wp-content/uploads/.htaccess 中创建:
<FilesMatch "\.(?i:php)$">
<IfModule !mod_authz_core.c>
Order allow,deny
Deny from all
</IfModule>
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
</FilesMatch>

三、被黑后的恢复流程
如果你已经发现网站被黑了——别慌,按以下顺序操作。这一节是上一篇 #42 日志审计的补充,聚焦于恢复和执行步骤。
🚨 恢复五步法
第一步:立即隔离。
# Nginx 层面只允许你自己的 IP
# 在 server 块中添加:
allow 你的IP;
deny all;
nginx -s reload
第二步:保留现场。
# 打包整站文件作为证据和回滚参照
tar -czf /root/hacked_$(date +%Y%m%d).tar.gz /www/wwwroot/你的网站目录/
mysqldump -u 用户名 -p 数据库名 > /root/hacked_db_$(date +%Y%m%d).sql
第三步:切换到一个干净的备份(首选)。
如果你有最近的完整备份(UpdraftPlus / 主机快照 / 自建备份系统),最安全的做法是:
- 用新目录还原备份
- 修改 DNS / Nginx 指向新目录
- 给还原的站点立刻更换密钥盐 + 所有管理员密码 + 数据库密码
- 验证正常后再处理旧的被黑目录
第四步:如果没有干净备份,手动清理(从易到难)。
# 4a. 覆盖核心文件(保留 wp-content 和 wp-config.php)
wp core download --force --skip-content --version=你的版本号
# 4b. 检查并清理上传目录中的 PHP 文件
find /www/wwwroot/你的网站目录/wp-content/uploads/ -name "*.php" -delete
# 4c. 对比主题和插件的完整性
# 逐一从官方源重新下载所有激活的主题和插件
wp plugin install --force 插件名1 插件名2 插件名3
wp theme install --force 主题名
# 4d. 检查并清理数据库
# 运行第一节提到的"查找多余管理员"和"可疑 option" SQL
第五步:恢复上线并加固。
- 更换所有密码(WordPress 管理员 + 数据库 + SSH + 主机面板)
- 更换密钥盐
- 运行本文第一、二节的全部加固措施
- 装上 #42 的安全监控体系(日志、告警、Fail2ban)
- 装上 #43 的 2FA
- 连续监控 72 小时
📄 事后分析模板
被黑之后写一份简短记录,防止重蹈覆辙:
事故时间:____年__月__日 __时 发现
入侵点(根因):_____________(如:某插件__版本未更新、弱密码、XML-RPC未禁用)
损失评估:_____________(用户数据?订单数据?SEO降权?)
修复耗时:___________ 小时
今后预防措施:1._____ 2._____ 3._____

四、完整安全检查清单
把本文和前面几篇文章的要点汇总成一份一张表就能用的检查单。打印出来,每季度核对一次。
📋 WordPress 安全加固逐项检查单
安装层面(一次性操作):
- [ ] 数据库表前缀已修改为非默认值(不是
wp_) - [ ]
wp-config.php中的 8 个密钥盐已更换为随机值 - [ ]
wp-config.php权限设置为 400 或 440 - [ ] 所有目录权限 755,文件权限 644
- [ ]
DISALLOW_FILE_EDIT已设为true - [ ] 网站文件的所有者不是
root(用专门的 PHP 用户运行)
持续加固(配置后永久生效):
- [ ] XML-RPC 已禁用(或配合 Nginx 限制 + Jetpack 白名单)
- [ ] WordPress 版本号已从 HTML、RSS、脚本链接中移除
- [ ] REST API 用户端点对未登录用户已禁用
- [ ] 登录错误信息已模糊化(不区分"用户不存在"和"密码错误")
- [ ] 用户名枚举(
?author=1)已禁用 - [ ] 管理员用户名不是
admin或网站域名 - [ ] Nginx 已配置禁止访问 readme.txt / license.txt
- [ ] Uploads 目录已禁止执行 PHP 文件
- [ ] 目录浏览(Autoindex)已关闭
监控与响应:
- [ ] 已安装安全活动日志(WP Activity Log 系列详见 #42)
- [ ] 关键事件(新增管理员/插件变更/批量登录失败)已配置邮件告警
- [ ] 已配置 2FA 并强制所有管理员启用(详见 #43)
- [ ] 备份系统正常运行(每日数据库 + 每周完整文件)(详见 #46)
- [ ] Fail2ban 或类似工具已配置暴力破解自动封禁
- [ ] 核心文件完整性校验(
wp core verify-checksums)可正常运行
定期动作(每季度):
- [ ] 运行一次
wp core verify-checksums确认核心文件未被篡改 - [ ] 检查管理员用户列表,确认无多余管理员
- [ ] 检查
/wp-content/uploads/中无 PHP 文件 - [ ] 检查 2FA 恢复码是否还有可用余额(余额不足时重新生成并保存)
- [ ] 确认备份可用:从备份中还原到测试站验证一次
- [ ] 检查所有未使用的主题和插件是否已删除(不是停用,是删除)
- [ ] 更新防火墙规则(检查 Fail2ban jail 是否正常误封了合法 IP)
🔗 安全工具速查
| 工具 | 用途 | 费用 |
|---|---|---|
| Wordfence | 综合安全 + 防火墙 + 扫描 | 免费版够用 |
| WP Activity Log | 活动日志与审计 | 免费版够用 |
| UpdraftPlus | 备份和恢复 | 免费版够用 |
| Sucuri SiteCheck | 在线病毒扫描(不用装) | 免费 |
| WPScan CLI | 命令行漏洞扫描 | 免费(非商业) |
| VirusTotal | URL/文件在线多引擎扫描 | 免费 |

总结
安全加固不是一劳永逸的事,但也不是需要技术博士学位才能做的事。这篇文章包含的所有措施,加起来大概需要你一个下午的时间来执行——回报是让 90% 以上的自动攻击对你无效。
五件现在就该做的事(5 分钟档 / 半小时档 / 半天档):
- 5 分钟内:确认
wp-config.php中DISALLOW_FILE_EDIT是true;确认表前缀不是wp_;更换密钥盐 - 半小时内:禁用 XML-RPC、隐藏版本号、限制 REST API 用户端点、禁止目录浏览
- 半天内:搭建 WP Activity Log 监控、配置 2FA 并强制管理员、部署 Fail2ban、做完完整检查单
如果被黑了不知道怎么办:
- WordPress.org 被黑修复指南(官方,最权威)
- Sucuri 恶意软件清除指南(商业公司但免费内容很扎实)
- WPScan 漏洞数据库(查插件/主题是否有已知漏洞)
- 如果你用的是托管主机(SiteGround / Cloudways),开一个工单直接问客服——他们见多了这种情况,知道该看哪里
WordPress 独立站学院 · 技术教程 · 安全防护 #45


