XSS是 跨站脚本攻击(Cross Site Scripting) ,不写为CSS是为了避免和层叠样式表(Cascading Style Sheets)的缩写混淆,所以将跨站脚本攻击写为XSS。
一、XSS原理
XSS是指攻击者通过向Web页面里面插入客户端脚本,通常是JavaScript编写的恶意代码,当用户浏览这个被嵌入恶意代码的页面时,就会运行被插入的JavaScript代码,达到攻击者的目的。
XSS 攻击类似于 SQL 注入攻击,SQL注入攻击中以SQL语句作为用户输入,从而达到查询/修改/删除数据的目的。
从上述内容可知, XSS 属于被动式且用于客户端的攻击方式。 受害者最终是用户。 不要以为受害者是用户,就认为跟自己的网站、服务器安全没有关系。但请注意,千万不要忘记网站管理人员也属于用户之一,这就意味着 XSS 可以攻击“服务器端”。因为管理员要比普通用户的权限大得多,一般管理员都可以对网站进行文件管理、数据管理等操作,而攻击者就有可能靠管理员身份作为“跳板”实施攻击。
二、XSS类型
XSS攻击主要分成 三类 : 反射型 、 存储型 、 DOM型 。
1、反射型XSS
反射型XSS 也被称为 非持久型XSS ,是现在最容易出现的一种XSS漏洞。
当用户访问一个带有XSS 代码的 URL 请求时,服务器端接收数据后处理,然后把带有 XSS代码的数据发送到浏览器,浏览器解析这段带有 XSS 代码的数据后,最终造成 XSS 漏洞。这个过程就像一次射,故称为反射型XSS。
2、存储型 XSS
存储型 XSS 又被称为 持久性 XSS ,存储型 XSS 是 最危险 的一种跨站脚本。
允许用户存储数据的 Web 应用程序都可能会出现 存储型XSS漏洞 ,当攻击者提交一段 XSS代码后,被服务器端接收并存储,当攻击者再次访问某个页面时,这段 XSS 代码被程序读出来响应给浏览器,造成XSS 跨站攻击,这就是存储型XSS。
存储型 XSS 与反射型 XSS、DOM 型 XSS相比,具有 更高的隐蔽性,危害性也更大 。它们之间 最大的区别在于反射型 XSS 与DOM 型 XSS 执行都必须依靠用户手动去触发,而存储型XSS 却不需要 。
3、DOM型 XSS
DOM的全称为 Document Object Model ,即文档对象模型,DOM通常用于代表在HTML,XHTML和XML中的对象。使用DOM可以允许程序和脚本动态地访问和更新文档的内容、结构和样式。
通过JavaScript可以重构整个HTML页面,而要重构页面或者页面中的某个对象,JavaScript就需要知道HTML文档中所有元素的“位置”。而DOM为文档提供了结构化表示,并定义了如何通过脚本来访问文档结构。根据DOM规定,HTML文档中的每个成分都是一个节点。
DOM的规定如下:
- 整个文档是一个文档节点
- 每个
HTML标签是一个元素节点 - 包含在
HTML元素中的文本是文本节点 - 每一个
HTML属性是一个属性节点 - 节点和节点之间都有等级关系
HTML的标签都是一个个节点,而这些节点组成了DOM的整体结构。
简单了解了DOM后,再来看看 DOM型XSS 就比较简单了。
可以发现,DOM本身就代表文档的意思,而基于 DOM型XSS 是不需要与服务器端交互的,它只发生在客户端处理数据阶段。
三、总结
XSS攻击可以简单划分为两类: 非持久型XSS攻击 和 持久型XSS攻击
非持久型XSS攻击 :顾名思义,非持久型XSS攻击是一次性的,仅对当次的页面访问产生影响。非持久型XSS攻击要求用户访问一个被攻击者篡改后的链接,用户访问该链接时,被植入的攻击脚本被用户游览器执行,从而达到攻击目的。
持久型XSS攻击 :持久型XSS,会把攻击者的数据存储在服务器端,攻击行为将伴随着攻击数据一直存在。
详细可分为三类:
反射型XSS :经过后端,不经过数据库
存储型XSS :经过后端,经过数据库
DOM型XSS :不经过后端,DOM- XSS是通过url传入参数去控制触发的。
四、解决方法
1. 输入验证和输出编码
- 对所有用户输入进行严格验证,只允许符合预期格式的输入
- 对输出到HTML页面的内容进行编码,确保特殊字符被转义
// 输出编码示例
function escapeHtml(text) {
return text
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
2. Content Security Policy (CSP)
- 通过设置CSP头部,限制页面可以加载的资源和执行的脚本
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com
3. 使用现代前端框架
- 现代前端框架(如React、Vue、Angular)默认会对输出进行转义,防止XSS攻击
// React会自动转义
function UserProfile({ user }) {
return <div>{user.name}</div>; // 自动转义,安全
}
4. HTTPOnly Cookie
- 设置cookie的HttpOnly属性,防止JavaScript访问cookie
Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Strict
5. 避免使用 innerHTML 和 outerHTML
尽量使用 textContent 或 createElement 等安全的 DOM 操作方法:
// 不安全:直接插入用户输入
element.innerHTML = userInput;
// 安全:使用 textContent
element.textContent = userInput;
// 安全:使用 createElement
const newElement = document.createElement("div");
newElement.textContent = userInput;
element.appendChild(newElement);
6. 过滤HTML标签
- 使用白名单机制,只允许特定的HTML标签和属性
// 简单的HTML过滤示例
function sanitizeHtml(html) {
const allowedTags = ["p", "br", "strong", "em", "u"];
return html.replace(/<([a-z][a-z0-9]*)[^>]*>/gi, (match, tag) => {
return allowedTags.includes(tag.toLowerCase()) ? match : "";
});
}
7. 使用专门的安全库
- 使用如DOMPurify等专门的HTML净化库
import DOMPurify from "dompurify";
const clean = DOMPurify.sanitize(dirty);