Skip to content

给网站做一次全链路加固:实战记录与清单

霜月极星
发布日期:
1 分钟阅读
编辑此文章

网站上线前我给自己安排了一门必修课:以攻击者视角把三个自有项目(本站、工具站、签到系统)完整审一遍,再按优先级修复。这篇是实战记录,方法论和清单都可以直接抄走。

易班自动签到系统的登录页(本地演示实例)

为什么是「对抗性」审查

普通的 code review 找 bug,对抗性审查找可被利用的链路:不问「这段代码对不对」,问「如果我是攻击者,从公网摸进来最短路径是什么」。这次审查的产出是:0 Critical / 0 High / 16 Medium / 17 Low——没有可直接沦陷的洞,但边缘配置、凭据治理、供应链、部署流程四类问题密布。

流程上有个值得复用的设计:独立审查 + 交叉复核。第一轮审查刻意不读任何旧审查产物(防止被已有结论锚定),审完再与历史报告合并比对,能发现单轮容易漏掉的盲区。另外全程只做静态分析与本地沙箱验证,绝不向生产环境发送测试流量——安全审查自己先把站打挂,是最难堪的事故。

边缘配置层:nginx 安全头

最典型的发现:全站缺失所有安全响应头。修复本身不难,难在知道 nginx 的一个经典陷阱——add_header 不跨级继承:只要某个 location 块里出现任何一条 add_header,server 级定义的全部响应头在它里面统统失效。所以静态资源这种自带 Cache-Control 的 location,必须逐条重申安全头:

server {
    ssl_protocols TLSv1.2 TLSv1.3;
    server_tokens off;

    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;

    location /static/ {
        # 自带 add_header → server 级安全头在此全部失效,必须重申
        add_header Cache-Control "public, max-age=2592000";
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        # …其余安全头同样逐条补齐
    }
}

配套的还有:/static 开了 1 年 immutable 缓存就必须给引用加版本号,否则改了 JS 用户端最长一年看不到更新;自签证书阶段 HSTS 只能设短周期甚至 max-age=0,否则切正式证书前回退自签会把用户浏览器「锁死」在报错页。

流程脆弱点:部署脚本的失败路径

部署脚本最危险的不是正常流程,而是失败之后做什么。审查发现旧脚本在解压校验失败时会清掉备份目录——一次失败的部署顺手删掉最后一个回滚点。修复原则:远端临时文件一律 mktemp 生成,解压后先校验 index.html 存在才允许切换,备份用 prev/old 双份轮换且失败路径永不删除。

另一个流程洞是「两份真相」:校验脚本与 nginx 配置各写了一份子路径清单,改 nginx 忘改脚本就静默漂移。修法是让校验脚本以 nginx 配置为唯一事实来源,解析 sub_filter 规则后再去扫页面里的 fetch/XHR/CSS 引用,不再手工维护清单。

应用层:三个真实修复

签到系统(Flask + SQLite)这次的修复最有代表性,挑三个讲:

口令明文回退自动迁移。配置里允许用 YIBAN_ADMIN_PASSWORD 明文设管理员口令,存在被读到明文的风险。现在首次启动检测到明文就自动转 scrypt 哈希写入 YIBAN_ADMIN_PASSWORD_HASH 并清空明文——我本地起演示实例时亲眼看到日志打出这行迁移提示,全程无感。

.env 解析白名单。source .env 加载配置等于把文件内容当 shell 执行,而公告栏这类用户可写的文本一旦混进 shell 元字符就是命令注入。改成逐行 key=value 解析、只导出 YIBAN_ 前缀的变量、非法键名跳过并告警,三层防御互相兜底。

链接协议白名单。协议与隐私文档支持 Markdown 链接,但 javascript:、data: 这类协议必须降级为纯文本——否则存的是存储型 XSS。

签到系统管理后台(本地演示实例,占位数据)

凭据与供应链

工具列表页

可复用的加固清单

小结

这轮加固给我的最大教训:安全不是一道开关,而是一组流程。单看每一项都是十分钟的小修,但只有把「审查 → 修复 → 复验 → 备份可回滚」串成闭环,才能在下次改动时不再把洞带回来。下一篇工具页里的易班自动签到,就是这套流程跑完之后的产品形态。

下一篇
从一个想法到上线:这个博客网站是怎么搭起来的