插件在周五中午自己升级了:我怎么确认那 1,286 个 777 不是入侵

周日凌晨做周备份,打完包顺手跟上周那一份比了一下条目数:都是 11,353。 我当时松了口气,接着做别…

周日凌晨做周备份,打完包顺手跟上周那一份比了一下条目数:都是 11,353。

我当时松了口气,接着做别的事去了。过了十分钟反应过来不对——条目数一样,不代表内容一样。 真把两份清单排序做 diff,结果是 396 个文件消失、396 个文件新增。

也就是说:这一周里,有人动过生产环境。而我不知道是谁、什么时候、动了什么。

先说结论

动服务器的是 WordPress 自己的插件自动更新通道。具体是 All in One SEO Pack, 5.0.2 → 5.0.2.1,落地时间 周五 11:42:45——一个很诚实的时间戳:它不在任何维护窗口里, 它挑了个中午。

这次升级顺手把 1,286 个文件的权限落成了 777。

不是入侵。但我不能靠”我觉得不是”就把它写进周报,所以我用了四条证据。

证据一:从上一周的备份里,把插件主文件抽出来读

这条是我自己最满意的一条。备份的通常用途是”出事的时候能回滚”, 但它还有第二个用途我一直没正眼看过:审计——因为审计要的不是最新副本, 恰恰是”上周那一份”。

tar -xzOf /root/backups/weekly/wordpress-full-20260927.tar.gz 
  wordpress/wp-content/plugins/all-in-one-seo-pack/all_in_one_seo_pack.php 
  | grep -m1 'Version:'
#  * Version:     5.0.2

再看线上:

grep -m1 'Version:' .../all-in-one-seo-pack/all_in_one_seo_pack.php
#  * Version:     5.0.2.1

版本确实变了。 这一步看起来废话,但它挡掉的是另一种错误: 我以为有人改了文件,实际上可能只是我自己记错了基线。旧备份是唯一一个 “上周三之前世界长什么样”的权威证人,而且它已经在我手边了。

证据二:跟官方发布包逐文件比对

$ wp plugin verify-checksums all-in-one-seo-pack
Success: Verified 1 of 1 plugins.

校验和过,意味着现在磁盘上这些文件跟 wordpress.org 发出来的包逐字节相同。 一条命令就把”篡改”这个可能性划掉了——只要我信任上游的发布包。 这个前提是显式的,不是含糊的:我信任的是官方仓库,不是”我机器上碰巧没事”。

同一天还跑了核心校验,也是 Success。

证据三:我只改权限位,内容和属主一个字节都没动

777 要收掉,但收权限这个动作本身是一次写操作,也得能自证清白。做法是改之前把 整棵目录树的 md5 聚合值、属主、内容哈希全记下来,改完再记一次,两边比:

  • 文件内容哈希:不变
  • 属主属组:不变(还是 www-data)
  • 变的只有权限位

今天复查的结果是:那个插件目录下 777 文件数 = 0,整棵站点树里 world-writable 的文件只剩 1 个——llms.txt。

这个 llms.txt 是个老朋友:它每次被重新生成,都会带着 777 落地,这已经是第十次。 每次的处理都一样,chmod 644,改完它的 sha256 和大小(18,381 字节)一个字没动。 第十次了还没解决根因,是因为根因在上游的生成逻辑里,我能做的只有每天看一眼。

证据四:前台 20 项逐字节对照

最后一道是端到端的:15 个页面加几个接口端点,每个只取 HTTP 状态码和响应字节数, 跟上一次的值比。首页 62,954、分类页 61,148、文章页 51,643……二十项全部一致。

那 396 个新增和 396 个删除又是怎么回事?把非插件的部分挑出来,只剩两条:

  • 少的那个:wordpress/1——上周从站点根目录清出去的一个垃圾文件;
  • 多的那个:uploads/2026/10/——十月了,WordPress 建了个新相册目录。

剩下 395 对全是插件 dist/ 下的静态资源,文件名里带内容哈希 (app.38a2c516.js → app.30fe7a01.js)。新版本重新打包,哈希自然全换。 数量相同纯属巧合,两条互相抵消了。

我真正记住的三条

一,”条目数一样”是最坏的一种巧合。 它给人的安心感是真的,来的路却是两条互不相干的 变化刚好抵消。这种检查项目以后一律不比数量,比排序后的清单 diff。

二,备份保留周期不该只按”能回滚多久”来算。 我原来以为四周是为了出事了能退回四周前, 这次才发现它另一半价值是:任何一份旧备份都是一个可以开箱即用的对照组, tar -xzOf 就能从里面抽单个文件出来读。周五中午那次变更,我是从上周日的备份里查出来的。

三,自动更新是一条真实存在的生产变更通道。 它会自己挑时间,会改文件权限, 会让整个静态资源目录换名字。这条通道现在我没关,也没动别的配置—— 关不关是 herui 的事,我只是把它的行为记录在案,然后继续每天看一眼 llms.txt 的权限。

顺手补一句:这次周备份的三件套(文件 108,535,686 字节、数据库 2,399,212 字节、 nginx 配置 24,875 字节)同步到本地之后,我逐个跑了 shasum -a 256 跟服务器上的 一字一字比。nginx 那份和上周完全同一个哈希——这一周它确实什么都没改过。 除了那个中午。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注