把官网缩成一个首页文件之后:我们省掉了哪些麻烦
上一篇《网站是怎么被黑的?》复盘了那次入侵:模板把网址原样输出 → 消毒只做一遍被拼接绕过 → 缓存文件被include当程序执行,三个小毛病串成一条远程命令执行链。修完之后我们做了个更彻底的决定——主站首页退化成一个纯静态的index.html,Nginx 直接关掉 PHP 解析。
一个月过去,回看这个决定,好处比当初预想的多。这篇文章就把账算清楚,也把代价说清楚。
一、先看两组数字
同一个域名,改造前后:
| 项目 | 旧站(PbootCMS) | 现在 |
|---|---|---|
| 站点体积 | 25 MB | 6.5 MB |
| 文件总数 | 830 个 | 113 个 |
| PHP 文件 | 140 个(index.php、admin.php、api.php、core/、template/) | 0 个 |
| 首页 | 模板 + 数据库 + 缓存动态渲染 | 单个 index.html,37 KB |
| 执行链 | Nginx → PHP-FPM → 模板 → 缓存 include | Nginx 直接返回文件 |
| 可写目录 | 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、限制第三方脚本来源、定期做文件哈希巡检。
六、什么样的站适合这么做
适合:
- 展示型企业官网:产品介绍、优势、案例、联系方式;
- 更新频率低(每月几次以内);
- 主要目标是"被搜到 + 建立信任 + 引导电话/微信咨询";
- 需要长期稳定、不想天天盯补丁和升级。
不适合:
- 有会员、订单、支付、库存等业务逻辑;
- 需要站内搜索、多语言大量页面、频繁由非技术人员更新;
- 需要复杂表单、用户提交内容并展示。
对后者,正确的做法不是"硬做成静态",而是把动态部分拆到独立子域或独立服务,主站保持静态。我们现在的结构就是这样:主站静态,博客、客服、工具站各自独立,一个出事不牵连另一个。
七、落地清单(照抄即可)
如果你也想把主站缩成一个首页文件,按这个顺序做:
- 首页写成单个 HTML,CSS/JS/图片放
/static/,引用加版本号(?v=20261021)便于缓存失效。 - Nginx 关闭 PHP:
location ~ [^/]\.php(/|$) { return 404; },并删掉所有指向fastcgi_pass的残留配置块。 - 敏感路径一律 404:
/.git、/backup、/config、.env、.sql、各类锁文件与说明文件。 - 上传目录禁止执行:
location ~* ^/(static/upload|upload)/.*\.(php|php5|phtml)$ { return 403; }。 - 权限收紧:站点文件属主
root,Web 用户只读;发布用替换,不用在线编辑。 - 静态资源设缓存:图片 30 天、CSS/JS 12 小时、HTML 不缓存。
- 第三方脚本加约束:能自托管就自托管,不能就用 CSP 限定来源域名,并监控其文件变更。
- 定期巡检:文件哈希基线 + 每周比对;重要改动前留快照。
- 别忘了同机其他站:动态站之间用独立用户隔离,别让一个站的漏洞变成整台机器的问题。
八、一句话总结
把首页做成一个静态文件,换来的不是"更安全"这四个字,而是三件很具体的事:可以被攻击的组件不存在了、被改了能立刻发现、恢复只需要替换文件。
安全从来不是"防住所有攻击",而是"让攻击的成本高于收益、让出事的代价可控"。对一个只需要展示的官网来说,砍掉整套 CMS,是这笔账里最划算的一刀。