XSS 跨站脚本攻击是如何进行的?
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
什么是 XSSXSS(Cross-Site Scripting)全称跨站脚本攻击——注意不是 CSS,所以缩写为 XSS。它的核心逻辑是:攻击者向网页注入恶意脚本,当其他用户浏览该页面时,脚本在他们的浏览器中执行,从而窃取数据、劫持会话或实施其他恶意操作。 这不是理论,是真实发生过的攻击。2014年,Twitter 就发生过大规模 XSS 攻击,攻击者通过一条推文注入了 JavaScript,数万名用户中招。 攻击的底层原理浏览器的解析流程要理解 XSS,先理解浏览器渲染页面的过程: 关键点在于:浏览器对 攻击的本质就是:让浏览器把攻击者控制的内容当成代码来执行。 三种 XSS 类型与攻击过程1. 反射型 XSS(Reflected XSS)场景:用户点击一个恶意链接,服务器把恶意脚本"反射"回页面执行。 攻击链: 具体案例: 假设有一个搜索功能,URL 是: 后端代码(有漏洞): 攻击者构造恶意链接: 当用户点击这个链接时:* 浏览器请求该 URL
这就是反射型 XSS——脚本不是存储在服务端,而是"反射"回来的。 2. 存储型 XSS(Stored XSS)场景:攻击者将恶意脚本提交到服务器(评论、用户名、个人简介等),所有访问该页面的用户都会中招。 具体案例: 假设一个论坛的评论功能: 攻击者提交评论: 所有访问该帖子的人,浏览器都会执行这段脚本,cookie 被窃取。 危害比反射型更大——因为攻击代码是永久存储的,影响所有访问者。 3. DOM 型 XSS(DOM-based XSS)场景:攻击脚本不经过服务器,完全在浏览器端通过 JavaScript 操作 DOM 执行。 具体案例: 攻击者构造链接: 浏览器解析时:*
关键区别:服务器完全没有参与,纯前端漏洞。 攻击的底层细节为什么 |
< | < |
> | > |
& | & |
" | " |
' | ' |
示例(Java):
java// 使用 OWASP Java Encoder
String safeOutput = HtmlUtils.htmlEscape(userInput);
// 输入: <script>alert('XSS')</script>
// 输出: <script>alert('XSS')</script>
// 浏览器渲染为文本,不执行
示例(JavaScript):
javascript// 危险:直接插入
element.innerHTML = userInput;
// 安全:使用 textContent
element.textContent = userInput;
// 或者手动转义
functionescapeHtml(str) {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
javascript// 白名单验证:只允许特定格式
functionvalidateInput(input) {
// 只允许字母、数字、中文
const validPattern =/^[a-zA-Z0-9\u4e00-\u9fa5]+$/;
return validPattern.test(input);
}
注意:输入验证不能替代输出编码。攻击者可以绕过简单的正则,但编码是浏览器层面的保障。
CSP 是浏览器层面的防御机制,通过 HTTP 头告诉浏览器"只允许执行来自这些来源的脚本"。
httpContent-Security-Policy: default-src 'self'; script-src 'self''unsafe-inline'
更严格的配置:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' https:; object-src 'none'; frame-ancestors 'none';
效果:即使攻击者注入了 <script>evil.com</script>,浏览器也会拒绝执行,因为脚本来源不在白名单中。
现代前端框架默认做了 XSS 防护:
// React:默认转义<div>{userInput}</div> // Vue:模板语法自动转义<p>{{ userInput }}</p> // 危险:v-html / dangerouslySetInnerHTML<div v-html="userInput"></div>
教训:使用 v-html 或 dangerouslySetInnerHTML 时要格外小心,确保内容可信。
┌─────────────────────────────────────────────┐│ XSS 防御纵深 │├─────────────────────────────────────────────┤│ 第1层:输入验证(白名单) ││ 第2层:输出编码(HTML 实体转义) ││ 第3层:CSP 策略(浏览器层面限制) ││ 第4层:框架防护(React/Vue 默认转义) ││ 第5层:HttpOnly Cookie(即使 XSS 也无法读 cookie)│└─────────────────────────────────────────────┘
HttpOnly Cookie 的关键作用:
// 设置 cookie 时添加 HttpOnly 标志res.cookie('session', token, { httpOnly: true });// 即使 XSS 执行了 document.cookie,也读不到这个值// 因为 HttpOnly cookie 对 JavaScript 不可见
这是最后一道防线——即使 XSS 攻击成功执行了脚本,攻击者也拿不到 session cookie。
XSS 的本质很简单:让浏览器执行了不该执行的代码。
防御的核心原则:永远不要信任用户输入
记住这个口诀:"输入是敌人,输出是战场"——在数据进入浏览器的那一刻,你就要决定它是"数据"还是"代码"。编码确保它是数据,不编码它就变成了代码。
阅读原文:原文链接