跳到正文
服务器与 .htaccess

真正有用的 WordPress .htaccess 安全规则

市面上打着 WordPress .htaccess 安全旗号的东西,大多是凑数的。真正能改变你受攻击面的规则其实很短——本文帮你分清哪些有用、哪些没用

发布于

市面上打着 “WordPress .htaccess 安全” 旗号卖给你的东西,大多是凑数的。真正能改变你受攻击面的规则其实很短:禁止在 wp-content/uploads 里执行 PHP、拒绝对 wp-config.php 的直接访问、关闭目录索引。那些流行的做法——屏蔽 xmlrpc.php “来阻止暴力破解”、隐藏你的 WordPress 版本、粘贴一份 200 行的恶意爬虫 user-agent 名单——从作用微乎其微到纯属做样子都有。下面就来分清哪些是哪些,以及为什么。

先说清楚一件事:.htaccess 只在 Apache(以及同样会读取它的 LiteSpeed)上起作用。在 nginx 上它会被完全忽略——文件就那么摆着,而你却以为自己受到了保护。如果你的主机跑的是 nginx,这些统统不适用,你需要改用 server / location 配置块。在花一小时去改一个服务器根本不读的文件之前,先用 curl -I https://yoursite.com 看一眼 Server: 响应头。

真正重要的那条规则:/uploads 里不许跑 PHP

这一条才值得做。wp-content/uploads 天生就是可写的——每一次媒体上传、每一个会保存文件的插件,都往这里写。如果攻击者把一个 .php 文件塞进了这个目录(通过有漏洞的上传处理程序、一个不校验 MIME 类型的图片字段、或者一个被入侵的插件),那么这只是个小麻烦,还是一次彻底的远程代码执行沦陷,区别就在于:当这个文件被请求时,服务器会不会去执行它。禁止执行,上传的载荷就只是一个躺在磁盘上、毫无作用的死文件。

把下面这段放进 wp-content/uploads/.htaccess(文件不存在就新建):

<FilesMatch "\.php$">
    Require all denied
</FilesMatch>

这是 Apache 2.4 的语法。在更老的 2.2 上,对应的写法是 Order Deny,Allow / Deny from all。在同一个文件里混用这两种方言,是 “加固” 之后突然冒出 500 Internal Server Error 的最常见原因——如果你一保存整个站点就挂了,几乎总是这个原因。用 apachectl -v 查一下你的版本。

保护 wp-config.php

wp-config.php 里存着你的数据库凭据和认证密钥。只要 PHP 在正常运行,对它的直接请求返回的是一个空白页面——PHP 会执行这个文件,而不是把它打印出来。风险在于失效的情况:一旦 PHP 崩溃、在迁移过程中被配置错了、或者处理程序被禁用,Apache 就会把这个文件当作纯文本发送出去,把你的数据库密码丢给任何来问的人。拒绝访问,就是为那糟糕的五分钟买的一份便宜保险:

<Files wp-config.php>
    Require all denied
</Files>

关闭目录索引

如果有人访问一个没有 index.php 的文件夹,而 Apache 又开着 Options +Indexes,它就会把里面的内容列出来——每一个备份文件、每一个你早就忘了的散落 SQL 导出文件。在全站范围内把它关掉:

Options -Indexes

严重程度不高,但确实存在,而且不花任何代价。

这就是老实的核心清单。你可以用 WordPress .htaccess 生成器 把这几条拼起来——外加正确的 2.4 还是 2.2 语法,免得把站点搞出 500——而不是从一篇为错误 Apache 版本写的论坛帖里复制粘贴。

不要做的事

屏蔽 xmlrpc.php “用于防暴力破解”。 这是人人都在重复、但说法本身就错的一条。没错,XML-RPC 的 system.multicall 方法历史上确实让攻击者能把大量登录猜测捆进一个请求里——这是真实的放大效应。但绝大多数暴力破解走的是对 wp-login.php 的普通 POST 请求,屏蔽 xmlrpc.php 对此毫无作用。暴力破解靠的是速率限制、强密码和双重验证来击退——而不是靠干掉一个端点。禁用 XML-RPC 确实有一个正当理由:它的 pingback 功能可以被滥用来做 DDoS 反射,所以如果你不用 Jetpack、手机 App 或 pingback,关掉它能缩小你的受攻击面。只是别骗自己说这是你的防暴力破解手段,因为它不是。

隐藏你的 WordPress 版本 / 移除 generator 标签。 删掉 readme.html<meta name="generator"> 标签,感觉像是在加固。可攻击者能在几秒钟内,从加载的静态资源查询字符串、区块编辑器标记,以及其他十几处蛛丝马迹里识别出你的版本。你什么都没藏住,只是让自己看起来很忙。

庞大的恶意爬虫 user-agent 和来源黑名单。 user-agent 只是一个可以随意伪造的 HTTP 头。这些名单你粘贴的当天就已经过时了,挡不住任何有本事的人,而 Apache 会在每一个请求上都跑一遍每一条正则——你在为零安全付出实打实的性能税。别用了。

wp-login.php 做 IP 锁定。 挺好,直到你的 ISP 给你换了个地址,把你自己锁在后台外面。只有在你有真正固定 IP 的情况下才可行。

作者枚举跳转(?author=1)。 大家为此粘贴的 .htaccess 重写规则本身并不完整——REST 端点 /wp-json/wp/v2/users 照样会列出用户名。堵住一条路径而另一条还开着,就是做样子。

还是搞不定?

如果某条规则把站点搞出了 500,那就是语法问题——把你最后加的那个配置块删掉再重载,立刻就能定位到它。如果某条规则看起来毫无效果,先确认你确实跑在 Apache 上,并且该目录启用了 AllowOverride(很多托管主机会限制它)。用 .htaccess 生成器 从一个已知可用的模板生成文件,留下真正重要的那三条规则,其余的都扔掉。