上一篇《网站是怎么被黑的?》复盘了那次入侵:模板把网址原样输出 → 消毒只做一遍被拼接绕过 → 缓存文件被 include 当程序执行,三个小毛病串成一条远程命令执行链。修完之后我们做了个更彻底的决定——主站首页退化成一个纯静态的 index.html,Nginx 直接关掉 PHP 解析。
一个月过去,回看这个决定,好处比当初预想的多。这篇文章就把账算清楚,也把代价说清楚。

一、先看两组数字

同一个域名,改造前后:

项目旧站(PbootCMS)现在
站点体积25 MB6.5 MB
文件总数830 个113 个
PHP 文件140 个(index.php、admin.php、api.php、core/、template/)0 个
首页模板 + 数据库 + 缓存动态渲染单个 index.html,37 KB
执行链Nginx → PHP-FPM → 模板 → 缓存 includeNginx 直接返回文件
可写目录data/、runtime/(上传、缓存必须可写)www 用户对站点目录不可写
后台admin.php 登录页 + 数据库无

现在站点的全部内容就是 index.html 加一个 static/ 目录(CSS 520 KB、字体 4.6 MB、图片 1.4 MB、JS 20 KB)。Nginx 里对应的一行是:

# 站点已转为纯静态,任何 .php 请求直接 404,不进入 php-fpm
location ~ [^/]\.php(/|$) {
    return 404;
}

就这一行,把上一篇里那条攻击链的最后一个环节直接删掉了。


二、好处一:攻击面不是"变小",而是"没有对应组件"

上一篇那条链之所以能走通,靠三个组件同时存在:会输出用户输入的模板标签、只过滤一遍的缓存机制、把缓存当代码执行的 include。

静态首页里,这三个东西一个都没有:

  • 没有模板引擎,就没有"把网址印进页面"的标签;
  • 没有服务端缓存,就没有"生成缓存文件"这一步;
  • 没有 PHP 解释器,就算有人真的往目录里写进一个 .php,Nginx 也只会回 404。

换句话说,不是我们把洞补得更牢了,而是这堵墙上已经没有那扇门了。这比任何过滤规则都可靠——过滤规则总有绕过手法,不存在的功能没有绕过手法。

同样消失的还有一整类老问题:

常见入侵入口静态首页下的状态
后台弱口令 / admin.php 爆破没有后台登录页
上传组件拿 shell没有上传接口
SQL 注入没有数据库
模板注入 / 反序列化没有模板与反序列化入口
缓存投毒后门没有服务端缓存文件
插件 / 主题后门没有插件体系
升级包覆盖补丁(上一篇第五条经验)没有升级包可覆盖

最后一条特别值得说:上一篇我们踩过的坑是——修复改在源码里,官方升级包一装,洞又开了。纯静态站点没有"升级"这个动作,也就不存在"升级把补丁冲掉"的风险。


三、好处二:被改了,一眼就能看出来

动态站被入侵后最难受的地方是"查不干净":木马可能藏在缓存里、藏在数据库的选项表里、藏在被改过的模板片段里,还会自动重建、自动过期、删了又长。

静态站的内容就是磁盘上的字节:

  • 比对文件哈希(md5sum / git status)就能知道有没有被改;
  • 改了什么,diff 一眼可见;
  • 回滚就是替换文件,不用清缓存、不用查库、不用重装程序。

我们现在的做法是:站点文件属主保持 root,www 只读;发布走"本地改 → 上传覆盖",每次发布前留一份快照。真要出事,恢复时间是分钟级,不是小时级。

顺带一提,权限本身就是一道防线:旧站为了上传和缓存,必须给 data/、runtime/ 写权限,那正是 webshell 最爱的落地目录;现在 Web 进程连写都写不进去。


四、好处三:快、省、好收录

  • 快:Nginx 直出 HTML,没有 PHP 启动、没有数据库查询、没有模板编译。静态资源配了 expires(图片 30 天、CSS/JS 12 小时),首屏体验稳定。
  • 省:不占 PHP-FPM 进程、不连数据库,小内存机器也能扛住突发流量;整站可以直接挂 CDN,源站压力接近于零。
  • 好收录:HTML 里 title、keywords、description、OG 标签、H1/H2 层级、语义化结构都是写死的,不存在"渲染失败导致爬虫抓到空白页"的问题;单页锚点结构让所有内容集中在一个 URL 上,权重不分散。
  • 好迁移:换服务器就是拷一个目录,不用导库、不用配 PHP 版本、不用改伪静态。

五、也要说清楚代价

写技术文章最怕只讲好处。这个方案有明显代价:

1. 不是字面意义的"一个文件"
首页主体是一个 HTML,但 CSS、JS、图片、字体仍然是分离的 113 个文件、6.5 MB(其中字体占 4.6 MB)。它省掉的是"动态程序",不是"静态资源"。

2. 内容维护不再能"点点鼠标"
没有后台就没有在线编辑。改一句文案要改 HTML,非技术人员不友好。我们的做法是:把常改的区域(比如首页的"最新文章"列表)用脚本每日同步,用标记包起来,避免手工改出错:

<!-- BLOG-LIST:START -->
...
<!-- BLOG-LIST:END -->

3. 单页不利于长尾关键词
所有内容挤在一个 URL 上,权重集中但抓不到细分词。这一块必须靠独立的内容站(比如本博客)来补,主站和博客站分工要维持住。

4. 表单、留言、搜索需要外接
没有后端就没有原生留言板和站内搜索,接第三方时同样要评估它的脚本安全和数据合规。

5. 静态 ≠ 不会被黑
这一点必须强调。静态站防护的只是"网站程序"这一层,下面这些仍然是真实入口:

  • 同机其他动态站(WordPress、Typecho 等)被攻破后横向移动;
  • 面板、SSH、FTP 的凭据泄露;
  • Nginx 配置错误导致的目录穿越或源码泄露;
  • 第三方脚本——首页从外部域名加载客服脚本,对方一旦被篡改,等于在主站执行任意 JS。

所以我们的配置里还保留着:敏感文件与目录一律 404、禁止上传目录执行 PHP、限制第三方脚本来源、定期做文件哈希巡检。


六、什么样的站适合这么做

适合:

  • 展示型企业官网:产品介绍、优势、案例、联系方式;
  • 更新频率低(每月几次以内);
  • 主要目标是"被搜到 + 建立信任 + 引导电话/微信咨询";
  • 需要长期稳定、不想天天盯补丁和升级。

不适合:

  • 有会员、订单、支付、库存等业务逻辑;
  • 需要站内搜索、多语言大量页面、频繁由非技术人员更新;
  • 需要复杂表单、用户提交内容并展示。

对后者,正确的做法不是"硬做成静态",而是把动态部分拆到独立子域或独立服务,主站保持静态。我们现在的结构就是这样:主站静态,博客、客服、工具站各自独立,一个出事不牵连另一个。


七、落地清单(照抄即可)

如果你也想把主站缩成一个首页文件,按这个顺序做:

  1. 首页写成单个 HTML,CSS/JS/图片放 /static/,引用加版本号(?v=20261021)便于缓存失效。
  2. Nginx 关闭 PHP:location ~ [^/]\.php(/|$) { return 404; },并删掉所有指向 fastcgi_pass 的残留配置块。
  3. 敏感路径一律 404:/.git、/backup、/config、.env、.sql、各类锁文件与说明文件。
  4. 上传目录禁止执行:location ~* ^/(static/upload|upload)/.*\.(php|php5|phtml)$ { return 403; }。
  5. 权限收紧:站点文件属主 root,Web 用户只读;发布用替换,不用在线编辑。
  6. 静态资源设缓存:图片 30 天、CSS/JS 12 小时、HTML 不缓存。
  7. 第三方脚本加约束:能自托管就自托管,不能就用 CSP 限定来源域名,并监控其文件变更。
  8. 定期巡检:文件哈希基线 + 每周比对;重要改动前留快照。
  9. 别忘了同机其他站:动态站之间用独立用户隔离,别让一个站的漏洞变成整台机器的问题。

八、一句话总结

把首页做成一个静态文件,换来的不是"更安全"这四个字,而是三件很具体的事:可以被攻击的组件不存在了、被改了能立刻发现、恢复只需要替换文件。

安全从来不是"防住所有攻击",而是"让攻击的成本高于收益、让出事的代价可控"。对一个只需要展示的官网来说,砍掉整套 CMS,是这笔账里最划算的一刀。

标签: 官网, 木马

添加新评论