给老 Drupal 站补 Host Header 防护,却先跟 cPanel 的文件锁打了两回合
公司一个还跑在 Drupal 9.1.5 + PHP 7.4 上的老官网,管理后台的状态报告里常年亮着一条安全警告:Trusted Host Settings 未配置。这条警告平时很容易被当成”又一条黄色小字”划过去,但它背后对应的是一类真实的攻击面——HTTP Host Header 欺骗(Host Header Spoofing)。
这条警告到底在防什么
浏览器访问网站时,HTTP 请求里会带一个 Host 头,告诉服务器”我要找的是哪个站点”——因为一台服务器上往往托管着很多个网站,服务器靠这个头来分发请求。问题在于:很多 Web 应用会无条件信任这个头的内容,而它是客户端随便就能伪造的。
攻击者直接对着服务器 IP 发请求,把 Host 头改成自己控制的域名,如果 Drupal 没有配置”可信主机列表”,它就会把伪造的域名当成自己的域名来用。由此衍生出两类经典攻击:
- 密码重置投毒:攻击者对管理员账号触发”忘记密码”,Drupal 用伪造的 Host 头生成重置链接——管理员收到的邮件里,重置链接指向的是攻击者的域名,一点击,重置 token 就送出去了;
- 缓存投毒:带伪造 Host 头的请求被 Drupal 缓存后,正常访客拿到的页面里,内部链接全部指向攻击者的服务器。
修复方式很便宜:在 settings.php 末尾加一段 trusted_host_patterns,白名单列出自己的域名。此后任何 Host 头对不上白名单的请求,Drupal 直接回 400 拒绝。
真正费劲的部分:文件被锁了两层
配置本身两分钟就能写完,但这台站点托管在 cPanel 上,编辑过程结结实实撞了两次墙。
第一层锁:文件本身是 0444。 Drupal 出于安全考虑,默认把 settings.php 的权限设成只读(0444)。cPanel 文件管理器里直接点编辑,保存时会被拒绝。解法:先把文件权限临时改成 0644,放开属主的写权限。
第二层锁:所在目录也是锁的。 权限改完再编辑,保存时又报错——
The system failed to create the file ”…/sites/default/settings.php.lock” … Permission denied
cPanel 的在线编辑器保存文件前,会在同目录下创建一个临时的 .lock 文件来防止并发编辑。而 Drupal 不止锁了 settings.php,连它所在的 sites/default 目录也锁成了 0555(只读+执行)——编辑器连锁文件都写不进去。解法:把 sites/default 目录临时改成 0755,这次保存立刻成功。
改完配置之后,两层权限都要记得锁回去
改完之后的收尾同样重要:目录改回 0555、文件改回 0444,把 Drupal 的保护恢复原样。最后刷新状态报告页面,那条常年亮着的警告变成了绿色对勾。
顺手确认的坏消息
处理这条警告时顺手核对了版本状态,结论不太乐观:
- Drupal 9 已于 2023 年 11 月停止支持——这个站点两年多没有收到过任何安全补丁;
- PHP 7.4 更早,2022 年 11 月就停止安全支持了;
- 从 9.1 升到当前的 Drupal 11 没有”一键升级”,必须先过渡到 10、处理废弃 API,是一个完整的迁移项目。
trusted_host_patterns 这一手只是把一个明确的、便宜的漏洞先堵上;真正的解药是立项迁移。
教训
- 状态报告里的安全警告值得逐条问一句”它在防什么”——“Trusted Host Settings 未配置”听起来抽象,展开看对应的是密码重置投毒和缓存投毒两类具体攻击,而修复只要几行配置;
- Drupal 的文件加固是两层的:文件权限 + 目录权限——在线编辑器(cPanel 这类)保存文件时通常要在同目录写临时文件,只放开文件本身的写权限是不够的;
- 临时放开的权限一定要当场锁回去——0444/0555 是 Drupal 刻意的安全设计,改完配置就恢复,不要留到”以后再说”;
- EOL 的 CMS 和 PHP 版本,修一条警告改变不了大局——记下来、立项、排期迁移,别让绿色对勾制造安全错觉。