---
tags: ["XSS", "CSRF", "Web Security", "OWASP", "CSP", "Security Header", "Content-Security-Policy", "Cross-Site Request Forgery"]
create time: 2026-05-18 10:30
---
# XSS 与 CSRF 攻击
## 概述
本文档系统梳理 Web 应用中最常见的两种客户端侧安全威胁——**跨站脚本攻击(XSS)**与**跨站请求伪造(CSRF)**。从攻击原理、分类场景到防御策略,结合 Go 后端和 React/TypeScript 前端的完整代码示例,帮助你在设计阶段就「把安全做进去」而非事后补漏。
> [!question] 思考题
> XSS 让你失去的是**用户的数据控制权**,CSRF 让你失去的是**用户的身份冒用权**。一个攻击注入恶意脚本,另一个则是伪装成合法请求。看似都与"前端"有关——它们根本区别在哪里?带着这个问题开始阅读。
---
## 一、XSS(跨站脚本攻击)
### 1.1 什么是 XSS?
XSS(Cross-Site Scripting)的本质是:**攻击者在目标网站中注入恶意 JavaScript 代码,当其他用户浏览该页面时,代码在其浏览器上下文中执行**。由于 JavaScript 在原始页面的同源策略下运行,它可以直接读取 Cookie、DOM、甚至以受害者身份发起 API 请求。
```mermaid
graph LR
A["攻击者注入
恶意脚本"] --> B["服务端存储
或反射回页面"]
B --> C["受害者浏览器
解析并执行"]
C --> D["Cookie 被盗
会话劫持 / 行为篡改"]
style A fill:#ffebee
style D fill:#b71c1c,color:#fff
```
> [!warning] 为什么叫 XSS 而不是 XS S?
> 为了避免与 Cascading Style Sheets(CSS)混淆,业界统一简写为 **XSS**(Cross-Site Scripting)。
### 1.2 XSS 三大类型
| 类型 | 注入方式 | 持久性 | 危险等级 |
|------|---------|--------|---------|
| **Stored(存储型)** | 提交到数据库(评论、个人资料),所有访问者受害 | ★★★★★ 持久 | 🔴 极高 |
| **Reflected(反射型)** | URL 参数嵌入返回页面,需诱导点击 | ★★★☆ 单次 | 🟠 高 |
| **DOM-based(基于 DOM)** | 纯前端 JS 将不可信数据写入 DOM | ★★★☆ 无服务器痕迹 | 🟡 中 |
#### 1.2.1 Stored XSS — 最致命
攻击者将恶意脚本存入数据库,每个访问该页面的用户都会中招。经典案例:留言板注入 ``。
```go
// ❌ 危险的做法 — 存储了原始内容,但渲染时用 text/template 或 Response.Write 直出
func SaveComment(db *sql.DB, userID int, content string) error {
_, err := db.Exec("INSERT INTO comments (user_id, content) VALUES (?, ?)", userID, content)
return err
}
// ⚠️ 注意:存数据的代码本身已是安全的(参数化查询防 SQL 注入)
// 危险在于后续渲染时没有做 HTML 转义 → Stored XSS
// ✅ 正确做法 — 存储不变,渲染时通过 html/template 自动编码输出
func SaveCommentSafely(db *sql.DB, userID int, content string) error {
// 纯文本场景:直接存原始内容
// 渲染用 {{.Content}} (html/template 自动转义 < > & " ')
_, err := db.Exec("INSERT INTO comments (user_id, content) VALUES (?, ?)", userID, content)
return err
}
```
#### 1.2.2 Reflected XSS — 钓鱼利器
攻击者构造恶意链接,诱骗受害者点击。恶意脚本随 URL 参数被服务端读取后反射回 HTML 响应中。
```mermaid
graph LR
normal["正常链接: /search?q=hello"] --> |"安全参数"| browser["浏览器安全渲染"]
evil["恶意链接: q=inject_script()"] --> |"服务端原样返回"| exec["浏览器执行脚本 → XSS"]
style normal fill:#e8f5e9
style browser fill:#e8f5e9
style evil fill:#ffebee
style exec fill:#b71c1c,color:#fff
```
```typescript
// ❌ React 中 dangerouslySetInnerHTML 使用不当可导致 Reflect XSS
function SearchResults({ query }: { query: string }) {
return (