6.4.1 XSS:输入验证与输出编码
一句话破题
XSS 攻击就是让你的网站帮攻击者执行 JavaScript 代码。防御的关键是:进来的要验证,出去的要编码。
核心价值
理解 XSS 能让你:
- 避免用户数据被盗
- 保护用户账户安全
- 通过安全审计
快速上手
React 默认防护
React 会自动转义 JSX 中的内容,这是第一道防线:
tsx
function Comment({ content }) {
// ✅ 安全:React 自动转义
return <div>{content}</div>
}需要警惕的场景
tsx
// ❌ 危险:绕过 React 防护
<div dangerouslySetInnerHTML={{ __html: userContent }} />
// ❌ 危险:动态创建脚本
const script = document.createElement('script')
script.src = userInput
document.body.appendChild(script)
// ❌ 危险:eval 执行
eval(userInput)使用 DOMPurify 清理 HTML
当确实需要渲染用户 HTML 时:
typescript
import DOMPurify from 'isomorphic-dompurify'
function SafeHtml({ html }) {
const clean = DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['p', 'b', 'i', 'em', 'strong', 'a'],
ALLOWED_ATTR: ['href'],
})
return <div dangerouslySetInnerHTML={{ __html: clean }} />
}配置 CSP 响应头
Content Security Policy 限制可执行的脚本来源:
typescript
// next.config.js
module.exports = {
async headers() {
return [{
source: '/:path*',
headers: [{
key: 'Content-Security-Policy',
value: "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
}]
}]
}
}避坑指南
新手最容易犯的错
- 认为"我只是展示用户输入,不会有问题"——展示本身就是执行的入口
- 使用
innerHTML或dangerouslySetInnerHTML却不清理内容 - 在 URL 参数中插入未验证的数据
