这一支写 Web 侧的漏洞机制和防御写法以机制为单位——因为同一条假设在 Web 里会换着名字反复回来(OGNL → Log4Shell → Spring4Shell 是同一条)。真实事件单独放在 事件分析 里;机制篇这边只在每篇的「它出现过的地方」留一行锚点。

每篇都走同一套结构,并且都有一段能跑的最小复现(Python 3 标准库,无外部依赖,复制即可运行):

这条假设是什么 → 它是怎么断的(可运行) → 它出现过的地方 → 为什么反复发生
              → 防御(按强度排序) → 边界与时效 → 小结 + 思考题

分类:信任在哪一环断掉

浏览器 ──▶ 边缘/解析 ──▶ 认证 ──▶ 授权 ──▶ 业务逻辑 ──▶ 出站请求 ──▶ 数据
   W4          W1 W5        W2       W3                      W8
                            W7 配置与暴露贯穿全程;W6 供应链在这条线之外(代码怎么装上来的)

W1 · 注入

数据被拼进一个会被解析的字符串。这一组共用第 1 篇的定义与三层防御。

W2 · 认证与会话

前提是"密码/库终会泄露",设计泄露之后的韧性。

W3 · 访问控制

W4 · 浏览器信任边界

围绕同源策略:它拦什么、不拦什么。

W5 · 内存与解析

输入的结构没被当回事:长度、边界、以及"检查之后到使用之前"这段时间。

W6 · 供应链

攻击者不攻破你,而是让你自愿装上他的东西。

W7 · 配置与暴露

W8 · 服务端出站

用户给一个"地址",你的服务端照着去取东西——地址是 URL 还是文件路径,机制是同一个。

贯穿全篇的几条原则

写到最后,你会发现同样几句话在不同章节反复出现——这不是重复,是它们本就是同一条:

默认拒绝、显式开放          黑名单必输(1) → 越权(12) → CORS(14) → 解析歧义(17) → 配置(20)
验证在信任之前             验签再反序列化(6) → JWT(9) → 用实收长度核验声称(16) → 验产物(19)
换掉那个会解析/执行的东西    参数化(2) / argv(4) / textContent(5) / 纯数据格式(6)
判断"它最终是什么",        参数化前先定死语法树(1) → 判断解析出来的 IP(22)
  而不是"它长什么样"         → 判断路径的落点(23)
校验和使用之间不能隔变换    过滤跑在解码之前(1) → 两个解析器不一致(17) → 补丁只解了一次码(23)
                          → DNS 重绑定(22) → 查完到改完之间世界变了(26)
改默认值,别写最佳实践      默认拒绝的白名单(25) / 框架默认鉴权(12) / 解析器默认关 DTD(24)
假设最坏已发生             密码存储假设库已泄露(7) → 密钥入库假设已泄露(21)
能力远超场景就是风险        表达式引擎(3) / 关掉多余功能(16) / CI 最小权限(19)

每篇的收录门槛

收    有可运行的最小复现,机制能写到行;今天还有人在写错的假设
不收  工具教程 / CTF 技巧 / 合规等保 / 只有"泄露了多少"而讲不清机制的事件

编号说明:24–26 是后补的三篇,编号排在末尾、但归属在上面各自的组里——按本页的分组顺序读即可。

链上安全的关系:基本没有,技术内容几乎不重叠,不必对照着读。判断边界见上一级目录。危险边界:只写补丁已发布多年的漏洞,复现用自搭最小靶子,不给现成可粘贴的完整攻击 payload。