本页目录

安全 I · 系统与 Web 攻防

对标:Stanford CS155 / MIT 6.858 / OWASP Top 10 | 前置:csapp-01/04(内存)、web 线、db 线、crypto 线 安全课的教学立场很明确——理解攻击是为了构建防御。这一页按"漏洞类别 + 其防御"的方式,讲清最常见、最重要的几类安全问题(内存安全、注入、XSS、CSRF、认证缺陷),每类都是"机理 → 为什么危险 → 怎么防"。这是防御性的知识:一个不懂这些攻击面的开发者,会无意中写出满是漏洞的代码。核心心法一句话:永远不要信任来自外部的输入。

学习层:哪一个信任边界让数据变成了代码?

1. 具体谜题:四条输入路径,四种不同的防线

系统收到四种输入:搜索框的查询值、评论正文、跨站表单和 URL 中的资源 id。每条输入都来自不可信主体,但它们穿越的解释器和授权边界不同。先预测:

  1. 哪一条路径需要参数化查询,哪一条需要输出编码?
  2. 仅有 HttpOnly cookie 能否阻止 CSRF?仅隐藏前端按钮能否阻止越权?
  3. 哪一条防线失效时,数据会跨入 SQL、浏览器脚本或对象授权的可信区域?

实验台只使用安全的标签化输入,不执行任何攻击载荷;它展示输入源、解释器、信任边界、阻断控制和最终 sink。先按边界预测漏洞类别与防御,再观察去掉一层防御后影响如何传播。

2. 最小模型:不可信数据穿越解释器或授权检查

把一条数据流写为

\[ U\xrightarrow{\text{validation/encoding/parameterization}}T\xrightarrow{\text{interpreter or policy}}S, \]

其中 U 是不可信输入,T 是被约束的数据表示,S 是 SQL、DOM、状态变更或资源对象。若输入在没有控制的情况下被解释器重新解析,代码/数据边界就被跨越;若资源 id 在没有服务端授权检查的情况下触达对象,身份/权限边界就被跨越。

3. 正式机制与不变量:防御要对应实际边界

  • 代码/数据不变量:参数化 API 保持查询结构与值分离;输出编码让评论保持文本;模板/命令 API 不能靠黑名单猜完所有语法。
  • 浏览器会话不变量:XSS 关注恶意代码在目标 origin 执行;CSRF 关注浏览器自动携带登录态发出非本意状态变更。HttpOnly、CSP、SameSite 和 CSRF token 作用不同,不能互换。
  • 授权不变量:每次服务端读取或写入资源都要依据当前身份和资源所有权/角色检查;前端隐藏控件不是安全边界。
  • 纵深不变量:输入校验、最小权限、内存安全、日志告警和隔离控制应叠加;单个框架默认值不能覆盖所有 sink。

攻击分类的价值在于定位边界,不在于背 OWASP 名称。一个系统可能同时存在 XSS、CSRF 和授权缺陷,修复一个并不会自动修复另两个。

4. 失败边界与迁移任务

实验不执行真实攻击、不代表具体框架版本的全部安全保证,也不覆盖旁路缓存、SSRF、竞态、供应链或物理侧信道。编码只保护它所覆盖的输出上下文;参数化只保护对应的查询接口;服务器授权检查还需要正确的租户和资源模型。

迁移任务:给 Medusa 的一个公网 endpoint 画数据流图,标出浏览器、边缘、FastAPI、数据库和日志的信任边界;为每个跨界点写输入校验、输出编码、参数化、认证、授权、CSRF/CSP 或隔离控制,并注明哪一个控制失效时仍有哪些保护。

JavaScript 失效时的静态读法:先定位输入跨入的解释器/授权对象,再选控制;四个场景不是同一道“安全常识题”。

输入场景 关键边界 首要控制 控制缺失时的 sink
搜索值进入 SQL 条件 数据 → SQL 结构 参数化查询 查询语义被改变
评论显示到页面 文本 → DOM/脚本上下文 输出编码/CSP 浏览器执行不可信代码
跨站状态变更表单 外部 origin → 登录态操作 CSRF token/SameSite 非本意状态变更
URL 资源 id 身份 → 资源授权 服务端对象级授权 越权读取/修改

1. 安全的思维方式

普通开发问"怎么让它工作",安全思维问"怎么让它出错、边界在哪、攻击者能控制什么"。三条基本原则贯穿全页:

2. 内存安全漏洞(系统层)

缓冲区溢出:写越界覆盖栈上返回地址的示意(教学用,讲防御:canary/ASLR/DEP)。

图 sec-01.3缓冲区溢出:写越界覆盖栈上返回地址的示意(教学用,讲防御:canary/ASLR/DEP)。

C/C++ 的内存 bug(csapp-04)不只是崩溃,是安全漏洞——攻击者可利用它控制程序:

防御(层层叠加):

3. 注入攻击(Web 层最经典)

SQL 注入:拼接 vs 参数化查询(数据与代码分离)。

图 sec-01.2SQL 注入:拼接 vs 参数化查询(数据与代码分离)。

注入的通用机理:把用户输入当作代码/命令执行——当数据和代码的边界没守住时发生。

通用防御原则:数据与代码分离 + 输入校验(白名单优于黑名单)+ 输出编码。注入类漏洞的共同解药都是"别让数据越界变成代码"。

4. 浏览器端攻击:XSS 与 CSRF

XSS(恶意脚本进你的页面) vs CSRF(你的登录态被别站利用) 机理对比 + 各自防御。

图 sec-01.1XSS(恶意脚本进你的页面) vs CSRF(你的登录态被别站利用) 机理对比 + 各自防御。

Web 前端(web-03)的两类经典攻击,机理正好相反:

XSS(跨站脚本):攻击者让恶意脚本在受害者浏览器里执行——通常因为网站把用户输入未经转义地放进页面(如评论区存了 <script> 标签,别人看到就执行)。危害:偷 cookie/token(web-02 会话)、冒充用户操作。

CSRF(跨站请求伪造):攻击者诱导已登录用户的浏览器向目标网站发出非本意的请求(利用浏览器自动带 cookie)——如诱导你点一个链接,偷偷用你的登录态转账。

读法:XSS 是"恶意代码进了你的页面"、CSRF 是"你的登录态被别的站利用"——理解这对区别,才能正确选防御(转义 vs token)。两者都源于 Web 的信任模型漏洞。

5. 认证与访问控制缺陷

6. 练习与要点

例 1(注入的边界思维) 看一段用字符串拼接构造 SQL 的代码,指出攻击者能怎么让输入越界成代码,然后改成参数化查询——理解"数据与代码分离"如何根治注入,不必真的去攻击任何系统,重点是学会识别这个反模式。

例 2(XSS vs CSRF 辨析) 给两个场景(评论区显示用户输入、一个自动提交的第三方表单),各判断是 XSS 还是 CSRF 风险、该用哪种防御——练"识别漏洞类别 → 选对防御"。

例 3(授权检查) 设计 Medusa 若加多用户后,"取某用户的数据"的端点该怎么在后端强制授权(不能只靠前端不显示)——把"认证 ≠ 授权、授权在后端"用到自己的系统设计。\(\blacksquare\)


下一页:安全 II——密钥、供应链与安全工程:把安全从"修漏洞"提升到"系统性的工程实践"——密钥管理、依赖供应链、以及安全左移。