01 · Web 应用安全:XSS / CSRF / SQL 注入
前端天天在跟这三类漏洞的「前端侧」打交道,本篇给一个跨前后端的统一框架:它们为什么会发生、各自的判断口诀、以及服务端怎么兜底。读完你能在任何一次代码评审里快速定位「这里会不会出事」。
速览卡
| 项 | 内容 |
|---|---|
| 一句话定位 | XSS / CSRF / SQL 注入的根因、判断口诀与服务端统一防御,通用 + 服务端侧 |
| 核心内容 | 三类漏洞的本质、各自的防御主手段、以及为什么「转义/过滤」都只是局部解 |
| 读完能回答 | 这段用户输入能不能直接拼 HTML?SameSite 到底防什么?参数化为什么能根治注入? |
| 相关板块 | A08 前端安全 | C16 服务端安全纵深 | N05 TLS 与证书 |
前端侧的具体做法(输入、DOM、第三方脚本)见 A08;本篇负责通用根因 + 服务端兜底。
一、先记三句口诀
| 漏洞 | 一句话根因 | 判断口诀 |
|---|---|---|
| XSS | 把「数据」当成了「代码」执行(HTML/JS) | "这段内容里可能混进用户输入,且会被当 HTML 渲染吗?" |
| CSRF | 浏览器自动携带凭证,无法区分请求是谁发起的 | "这个请求是不是只靠 Cookie 验身份、且没有额外的防伪校验?" |
| SQL 注入 | 把「数据」拼进了「SQL 语句」 | "这里是不是用字符串拼接拼出了 SQL,而不是参数绑定?" |
共同点:信任了不该信任的输入,并且没有在"解释边界"上做正确的事。 防御的正确姿势几乎都不是"过滤坏东西",而是"明确区分数据与代码/指令"。
二、XSS:三个变体的共同本质
2.1 三种形态
| 类型 | 触发点 | 典型场景 | 危害 |
|---|---|---|---|
| 存储型 | 恶意内容先存到后端,别人访问时渲染 | 评论、昵称、富文本 | 最大:受害者是所有看到的人 |
| 反射型 | 恶意内容在 URL 参数里,立即回显 | 搜索框 ?q=<script> | 需诱导点击,但钓鱼链接防不胜防 |
| DOM 型 | 纯前端 innerHTML / eval 处理数据 | SPA 里拼接 HTML | 后端看不到,WAF 也拦不住 |
2.2 为什么「过滤 <>」靠不住
过滤黑名单(<script>、onerror)总有绕过:编码变体、<img src=x onerror=...>、事件属性、javascript: 协议、SVG 里的脚本……
正确的分层防御:
| 层 | 手段 | 解决什么 |
|---|---|---|
| 输出编码 | 按上下文编码(HTML/属性/JS/CSS/URL 各有各的编码) | 把数据当文本而不是代码 |
| CSP | Content-Security-Policy 限制脚本来源 | 即使注入成功,也拦下执行 |
| HttpOnly Cookie | JS 读不到会话令牌 | 把 XSS 的伤害从「偷凭证」降级为「改页面」 |
| 输入校验 | 白名单校验(邮箱、手机号格式) | 缩小可输入范围,但不替代上面三层 |
判断框架:默认不信任任何字符串当 HTML 用。 React/Vue/Flutter 的默认文本渲染是安全的;危险的是
dangerouslySetInnerHTML/v-html/innerHTML——用了就要想清楚数据来源与编码。
三、CSRF:问题出在「浏览器自动带凭证」
3.1 攻击成立的两个前提
1. 请求靠 Cookie(或基础认证)验身份 —— 浏览器会自动带上
2. 没有额外的防伪校验攻击者只是让你在已登录的状态下访问一个页面,页面里的表单/图片就会带着你的 Cookie 发请求。
3.2 三个层次的防御
| 手段 | 做法 | 覆盖度 |
|---|---|---|
| SameSite Cookie | SameSite=Lax(默认)或 Strict | 拦掉跨站的自动携带,主防御 |
| CSRF Token | 表单里带服务端签发的一次性 token,提交时校验 | 拦掉"没有 token 也能过"的场景 |
| 同源校验 / 自定义头 | 校验 Origin/Referer,或要求自定义请求头 | 补充,尤其 API 场景 |
SameSite 的关键认知:它防的是跨站(site = 注册域),不是跨域。 同一域名下的子路径、同一站点下的不同子域属于同一 site,SameSite 拦不住——此时才需要 CSRF Token。
现代浏览器
Lax已是默认,但仍建议显式声明,并配合 CSRF Token 做纵深。
3.3 前后端分别该做什么
| 侧 | 动作 |
|---|---|
| 前端 | 登录/会话用 HttpOnly Cookie;写操作(POST/PUT/DELETE)不要用纯链接 GET 触发副作用 |
| 后端 | 关键操作校验 CSRF Token;校验 Origin;对敏感操作二次确认(改密、支付) |
四、SQL 注入:参数化是根治,不是选项
4.1 本质
# ❌ 拼接:用户输入变成 SQL 的一部分
sql = "SELECT * FROM users WHERE name = '" + name + "'"
# ✅ 参数化:数据与语句分离,数据库引擎区分对待
sql = "SELECT * FROM users WHERE name = %s"拼接把「数据」混进「语句」;参数化让数据库知道哪些是值、哪些是结构——这正是与 XSS 完全同构的解法(数据与代码分离)。
4.2 为什么「过滤 '」「WAF」都不是根治
- 过滤单引号:编码、注释符
--、\转义都有绕过。 - WAF:能挡常规攻击,但挡不住业务逻辑里新出现的拼接点,且会产生误杀。
- ORM 自动转义:只要 ORM 的参数化查询路径被正确使用就是安全的;但原生 SQL / 动态拼接依然危险。
4.3 服务端兜底清单
| 手段 | 说明 |
|---|---|
| 参数化查询 / ORM 绑定 | 唯一根治手段,默认使用 |
| 最小权限的 DB 账号 | 应用账号只给需要的库/表权限,注入拿不到管理员权限 |
| 输入校验 | 类型/长度/格式白名单,减少攻击面(但不替代参数化) |
| 错误信息不外泄 | 不要回显 SQL 报错细节给客户端 |
注入不只是 SQL:命令注入(拼 shell)、模板注入(SSTI)、路径穿越是同一思想在不同解释器上的重演。看到一个「字符串拼进另一个语言」的地方,就要警觉。
五、服务端统一防御:一张检查表
| 检查项 | 默认动作 |
|---|---|
| 任何用户输入进 SQL/Shell/模板 | 参数化 / 明确转义,不拼接 |
| 任何用户内容进 HTML/属性/JS | 按上下文编码;禁止裸 innerHTML |
| 会话凭证 | HttpOnly + Secure + SameSite Cookie;不用 localStorage 存 token |
| 写操作 | CSRF Token + 同源校验;敏感操作二次确认 |
| 错误返回 | 统一错误体,不吐堆栈/不吐 SQL |
| 权限 | 接口层校验 + 数据层过滤(防 IDOR) |
| 依赖 | 锁文件 + 定期漏洞扫描(SCA,见 S07) |
| 传输 | 全站 HTTPS + HSTS(见 N05) |
这套检查表可以固化成代码评审 checklist 与 CI 里的安全扫描,比靠个人记性可靠得多。
六、自检清单
- [ ] 能说清三类漏洞各自「信任了什么不该信任的输入」
- [ ] XSS 知道按上下文编码,且知道
<>过滤不可靠 - [ ] 知道 CSP、HttpOnly 各解决 XSS 的哪一部分
- [ ] 知道 SameSite 防的是跨站,不是跨域;何时仍需要 CSRF Token
- [ ] SQL 一律参数化,且知道「过滤单引号」为什么不够
- [ ] 错误信息不外泄,应用 DB 账号最小权限
- [ ] 见过「字符串拼进另一种语言」的场景都能拉响警报
七、常见误区
| 误区 | 事实 |
|---|---|
"过滤了 <script> 就安全" | 黑名单总有绕过;按上下文编码 + CSP 才是正解 |
| "XSS 只在前端" | 存储型把恶意内容存后端,所有访问者都会中招 |
| "用了 HTTPS 就不怕 CSRF" | HTTPS 防窃听,防不了「已登录会话被利用」 |
| "SameSite=Lax 就万事大吉" | 同站子域、GET 触发副作用、旧浏览器都可能绕过 |
| "过滤单引号能防 SQL 注入" | 编码与注释绕过多;参数化才是根治 |
| "ORM 一定安全" | ORM 的参数化路径安全,原生 SQL/动态拼接依然危险 |
| "输入校验就能防注入" | 校验减少攻击面,但不能替代数据与代码分离 |
| "报错信息给用户看方便调试" | 泄露表结构/路径/依赖信息,是攻击者的地图 |
八、动手练习
练习 A:给一段渲染做"安全体检"
// 这三行哪几行有风险?分别是什么类型的 XSS?怎么修?
<div>{user.nickname}</div>
<div dangerouslySetInnerHTML={{ __html: article.content }} />
<img src={user.avatarUrl} />练习 B:追一次注入
给你一个搜索接口 GET /search?q=...,后端用字符串拼接拼出 SQL。说出三种修复方式,并说明哪种是根治。
练习 C:设计一次"改绑手机号"
要求:已登录、HTTPS、防 CSRF、防撞库。列出你会加的全部防护,并说明每一层挡住的是什么攻击。
相关文档
本区
- 02 · 认证授权体系 —— 凭证模型与授权框架,CSRF 的受害者正是「只靠 Cookie 验身份」
- S · 安全计划
其他域
- 08 · 前端安全 —— XSS / CSRF 的前端侧做法
- 16 · 服务端安全纵深 —— 注入/SSRF/密钥/供应链的服务端落地
- 03 · 认证与授权 —— token 存放与 CSRF 的关系
- 04 · 浏览器与网络 —— Cookie 与 SameSite 的浏览器行为