这一支写 Web 侧的漏洞机制和防御写法,以机制为单位——因为同一条假设在 Web 里会换着名字反复回来(OGNL → Log4Shell → Spring4Shell 是同一条)。真实事件单独放在 事件分析 里;机制篇这边只在每篇的「它出现过的地方」留一行锚点。
每篇都走同一套结构,并且都有一段能跑的最小复现(Python 3 标准库,无外部依赖,复制即可运行):
这条假设是什么 → 它是怎么断的(可运行) → 它出现过的地方 → 为什么反复发生
→ 防御(按强度排序) → 边界与时效 → 小结 + 思考题
分类:信任在哪一环断掉
浏览器 ──▶ 边缘/解析 ──▶ 认证 ──▶ 授权 ──▶ 业务逻辑 ──▶ 出站请求 ──▶ 数据
W4 W1 W5 W2 W3 W8
W7 配置与暴露贯穿全程;W6 供应链在这条线之外(代码怎么装上来的)
W1 · 注入
数据被拼进一个会被解析的字符串。这一组共用第 1 篇的定义与三层防御。
- 第 1 篇:注入的一般形式——为什么「过滤危险字符」是错的解法
- 第 2 篇:SQL 注入——参数化都用了,为什么还会中招
- 第 3 篇:表达式语言注入——你以为在填值,其实在求值
- 第 4 篇:命令注入——shell 才是那个解析器
- 第 5 篇:XSS——注入的目标是别人的浏览器
- 第 6 篇:不安全反序列化——「还原对象」本身就是执行
- 第 24 篇:XXE——解析器替你把文件读了出来
W2 · 认证与会话
前提是"密码/库终会泄露",设计泄露之后的韧性。
- 第 7 篇:密码存储——为什么快哈希是错的
- 第 8 篇:会话与令牌——签发、存储、撤销的一整条命
- 第 9 篇:JWT——签名是给谁看的
- 第 10 篇:OAuth 与 MFA——把第三方和第二因子接进来
W3 · 访问控制
W4 · 浏览器信任边界
围绕同源策略:它拦什么、不拦什么。
- 第 13 篇:CSRF——浏览器替受害者带上了 cookie
- 第 14 篇:CORS——给同源策略开的口子别开成敞口
- 第 15 篇:Clickjacking 与 postMessage——窗口之间的信任
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。