夜雨聆风学习资料网

ARTICLE · 1344537

把博客的 14 个插件翻了一遍,做了一次安全复核

把博客的 14 个插件翻了一遍,做了一次安全复核

博客跑久了,插件会越来越多。装的时候都想着“先用着”,后来版本、权限、缓存、日志、证书这些事,就慢慢堆在角落里。前段时间我零零散散修过几次,但都是哪儿响动修哪儿,没有从头到尾看过。这次干脆停下来,把站点完整查了一遍。

这不是渗透测试。我没去试弱口令,也没跑扫描器,更没抓包。基本上就是看代码、看配置、看日志、看数据库,再用外部访问和回源直连做对比。确认有问题了,才分成几批去改。每改一项,先备份,再验证,最后把回滚命令记下来。

先盘家底

我先数了数,站点上有 14 个已启用插件。逐个打开入口文件、Action、配置、文件读写和外部请求看。版本没有看后台显示,而是用 Typecho 自己的 parseInfo 读文件,省得后台一个版本、实际文件另一个版本。

看完之后,问题大概能归成几类:插件运行时产生的文件放在 Web 根里,知道地址就能下;管理接口没有登录校验,只靠“别人不知道”;出站请求把 TLS 证书校验关了;站点在 CDN 后面,源站拿到的 IP 不是访客 IP。

这几类问题都有个共同点:页面平时能打开,所以很容易被忽略。但它们不需要站点出故障,也能被利用。

能直接下载的文件,先堵上

插件跑起来会生成 cache、data、logs 这些目录。里面有缓存、日志、访客 IP,有的还放着第三方接口的 token。按理说这些文件不该让浏览器直接访问,但之前有些目录就在 Web 根内,地址猜得到就能下。

我没有挨个改插件,而是在 nginx 里统一兜底:插件目录下的 cache、data、logs 和 usr/cache 一律返回 404。RssManage 的 rss.json 和 favicons 是前端要用的,单独放行,免得把正常功能一起封了。

location ~* ^/usr/plugins/[^/]+/(cache|data|logs)(/|$) {     return 404; }

改完以后,我拿了 16 个敏感地址做测试,外部访问和回源直连都是 404。首页、文章、sitemap、feed、rss.json、favicons 还是 200。这个顺序挺重要:先确认哪些文件真的不该公开,再统一封,不要一边封一边把页面弄坏。

管理接口不能靠“别人不知道”

uSitemap 有几个管理动作,能删 robots.txt,也能往根目录写文件。之前没有登录校验,知道地址就能调。这个问题不是功能写错了,而是默认把管理接口当成了公开接口。

我加了三层:管理员登录校验、同源 Origin/Referer 校验,以及删除文件时只接受 32 位十六进制的 key。AutoSlug 的翻译接口也按同样的思路处理,没登录直接拒绝。

验证的时候不看代码,直接发请求。未登录调用 4 个管理动作,全部 403;sitemap.xml 和 robots.txt 正常 200。管理功能要能用,但只能给登录后的管理员用。

CDN 后面的 IP,不是眼睛看到的那个

站点在 CDN 后面,源站看到的 REMOTE_ADDR 是回源 IP,不是访客 IP。SafeMange 之前拿它做限速,结果把 CDN 回源 IP 封了,所有访客一起 403。XQLocation 又无条件相信 X-Forwarded-For 的第一个 IP,直连源站的人可以伪造评论归属地。

这两个问题看着是插件的事,根子都在“代理链怎么取 IP”。我的做法是:先把 CDN 的回源网段配成可信代理;只有 REMOTE_ADDR 命中可信网段,才去看 X-Forwarded-For;然后从右往左,取第一个不可信的 IP;如果整条链都不可信,就退回 REMOTE_ADDR。

有个地方不能图省事:可信代理别填 0.0.0.0/0。那等于告诉程序“谁都是代理”,任何人都能伪造来源 IP,防护就成摆设了。

配好之后,日志里开始出现真实访客 IP,不再是一排回源地址。SafeMange 的运行时文件也从 320KB、1,145 个 IP,降到大约 102KB、3 个 IP。100 次解码加编码的平均耗时,从 14.45ms 降到 1ms 左右。问题解决了,性能也顺带回来了。

出站请求也别把证书校验关了

RssManage 抓 RSS、CommentNotifier 发 SMTP、Links 取邮箱头像,之前都把 TLS 证书校验关了。原因不难理解:开了校验,个别源站证书有问题就会失败;关掉最省事。但省事的方向错了。

这次全部打开 verify_peer 和 verify_peer_name。打开以后,96 个 RSS 源里 90 个成功,6 个失败。真正跟证书有关的只有 2 个,一个是源站证书链异常,一个是证书过期。其余是 HTML 不是 RSS、内网地址被拒、连接超时这些老问题。

我没有为了这 2 个源把全局校验再关掉。安全默认值一旦为个别源回退,等于所有源都不设防。可以停用,可以单独加白名单,也可以等源站修证书,但不能把整条链路降级。

CommentNotifier 用企业邮箱重新发了测试邮件,发送成功。Links 的头像接口加了域名白名单和 1 小时缓存,缓存文件本身也被 nginx 挡住了。出站请求和入站请求一样,都值得认真对待。

性能和日志,顺手一起收拾

SafeMange 原来的问题是每个请求都要读 320KB 的 JSON,解码、编码、再写回去。1,145 个 IP 的时候,平均 14.45ms 一次。单看不大,但它是每个动态请求都要付的成本。

可信代理配好、旧封锁记录清掉之后,运行时文件只剩 3 个 IP,大约 102KB,耗时 1ms 左右。没改架构,也没上 Redis,先把数据量降下来,问题就小了一大半。

其他几项也是类似思路。WeChatDraft 的缓存从 Web 根移到 Web 根之外,目录 0700,文件 0600。RssManage 的 cron 日志装了 logrotate,5MB 轮转、保留 3 份、压缩加 copytruncate,原来 19.5MB 的日志一次清掉。LlmsTxt 加了 Cache-Control: public, max-age=3600,全文条数限制到 500。SiteSearch 去掉了每页 session,CORS 改成白名单,限速改成按 IP 的文件锁。

这些事情单拎出来都不算高危,但堆在一起,就是站点变慢、磁盘变满、日志里找不到重点的原因。

修完再查一遍,又翻出几件事

批次 1 到 6 做完后,我没有直接收工,而是又做了一次只读复核:14 个插件版本、敏感路径、管理动作、CORS、TLS、缓存、日志、备份,全部重新看一遍。

大部分结果符合预期。16 个敏感路径 404,4 个管理动作 403,TLS 1.0/1.1 在 CDN 边缘和源站都被拒绝,证书校验通过,近 300 行访问日志没有 5xx。之前修 Typecho SSRF 漏洞 和 PHP 漏洞 的时候,也是这个流程:先确认影响,再小步改,最后复测。

但复核也翻出几个之前没注意的问题。PHP-FPM 的 display_errors 还是 On,程序一报错,路径和代码可能直接输出到浏览器。/install/ 下的 SQL 结构文件能直接下载。安全响应头缺了 HSTS、X-Frame-Options、X-Content-Type-Options、Referrer-Policy。Web 根和几个目录是 0777,上传目录也没禁止执行 PHP。

还有几项是运维层面的:面板的 cron 日志已经很大,没有轮转;其他几个子域还开着 TLS 1.0/1.1;后台登录缺独立的限速;备份只存在本机。它们不一定马上出事,但都属于“现在不做,以后还是要做”的事。

这次先处理了两个最直接、风险也最低的。nginx 那边禁止 /install/ 和 /install.php,禁止上传目录执行 PHP,加上 HSTS、X-Content-Type-Options、X-Frame-Options、Referrer-Policy。PHP 那边把 display_errors 和 display_startup_errors 关掉,log_errors 保持开启。

验证结果:7 个安装目录地址全部 404,4 种上传 PHP 后缀全部 403,首页、文章、sitemap、feed、后台登录仍然 200。FPM 实际生效值是 Off / Off / On,首页和文章 HTML 里不再出现 PHP 错误字样。错误还是会写日志,只是不再给访客看。

剩下的目录权限、日志轮转、maxLogs、相邻子域 TLS、后台防护、异地备份,没有一次性全动。它们大多属于收尾工作,不影响站点当前运行,慢慢排就行。

这次留下的几个教训

只读先行,真的能省很多事。先收集证据,再决定改什么。很多“看起来有问题”的地方,实际测一下可能不是问题;很多“看起来正常”的地方,反而一测就露馅。

一次只改一项。改完一项,验证一项,出问题能立刻定位。最怕的是一次改十个地方,最后不知道是哪一步把站点弄挂了。

备份和回滚要写清楚。不是“我记得怎么改”,而是具体到文件、路径、校验和、恢复命令。真出事的时候,脑子通常是乱的。

外部和回源都要看。CDN 会缓存、会改响应头、会隐藏真实 IP。只看外部,可能看到的是缓存;只看源站,又可能漏掉边缘的行为。

日志和缓存也是敏感数据。不是只有数据库才叫数据。访客 IP、访问记录、第三方 token,落在 Web 根里就是可下载的文件。

安全默认值不要为个别源回退。一个源证书坏了,可以停用、可以单独白名单,但不要把所有源的校验都关掉。

最后,修完一定要复测。代码 diff 只能说明“改了”,不能说明“生效了”。真正让人放心的是请求返回 404、403、200,是日志里没有新错误,是证书能验过去。

写在最后

这次审计没有把站点变成“绝对安全”,也不存在这种事。它只是把明显的问题收掉,把不知道的状态变成知道。对一个个人博客来说,这就够了。

小站也是站,个人博客也是别人能访问的入口。平时安安静静的时候,正是适合做这些事的时候。等页面打不开、流量异常、评论被刷,再回头查,往往就晚了。

回首页,搜索你想要的文档

在首页搜索框输入关键词,快速定位资料

文库首页搜索指引 立即搜索

相关学习资料