攻击_XSS
前言
Github:https://github.com/HealerJean
一、XSS
跨站脚本攻击(
Cross-Site Scripting,简称XSS)是一种常见的Web安全漏洞,攻击者通过向网页中注入恶意脚本,使得其他用户在浏览该页面时执行这些脚本,从而实现对用户的攻击。XSS攻击主要发生在客户端(通常是浏览器),因此也被称为“客户端脚本攻击”。
1、XSS 基本原理
XSS 攻击的核心在于:用户输入的数据未经充分过滤或转义,就被直接嵌入到网页中,从而被浏览器当作可执行的脚本运行。
例如,一个网站的搜索框如果直接将用户输入的内容显示在页面上,攻击者就可以输入类似如下的内容:
<script>alert('XSS')</script>
如果网站没有对用户输入进行过滤或转义,这段脚本就会在其他用户的浏览器中执行,从而导致攻击。
2、XSS 的三种主要类型
1)反射型 XSS(Reflected XSS)
- 定义:恶意脚本作为请求的一部分被发送到服务器,服务器未经过滤或转义就将脚本反射回浏览器执行。
- 攻击方式:通常通过诱导用户点击一个包含恶意代码的链接(如邮件、即时消息、社交平台等)。
- 特点:攻击不会存储在服务器中,是一次性的。
示例 URL:
http://example.com/search?q=<script>alert('XSS')</script>
2)存储型 XSS(Stored XSS)
- 定义:恶意脚本被提交并存储在服务器(如数据库、评论、用户资料等),当其他用户访问该页面时,脚本被加载执行。
- 攻击方式:攻击者将恶意脚本提交到网站中(如论坛、留言板、博客评论等),一旦其他用户访问该页面就会触发攻击。
- 特点:攻击具有持久性,危害范围广。
示例场景: 攻击者在论坛中发表一个包含 <script> 标签的评论,所有查看该评论的用户浏览器都会执行该脚本。
3)DOM 型 XSS(DOM-based XSS)
- 定义:攻击不依赖于服务器响应,而是由于前端
JavaScript直接操作用户输入的数据,导致恶意脚本被执行。 - 攻击方式:攻击者通过修改页面的
DOM(文档对象模型)来触发脚本执行。 - 特点:攻击完全发生在客户端,服务器不会处理恶意脚本。
示例:
document.write(location.hash);
如果用户访问的 URL 是:
http://example.com/#<script>alert('XSS')</script>
那么 location.hash 的值将被直接写入页面,导致脚本执行。
二、XSS 攻击的危害
- 窃取用户敏感信息:攻击者可以通过脚本读取用户的
Cookie并发送到自己的服务器,从而盗取用户身份。 - 钓鱼攻击:插入伪造的登录框、表单,诱导用户输入账号密码。
- 会话劫持(
Session Hijacking):利用获取的Cookie或Session信息冒充用户进行操作。 - 网页篡改:修改页面内容,误导用户或破坏用户体验。
- 蠕虫传播:利用
XSS编写自动传播的脚本,感染更多用户。 - 拒绝服务攻击(
DoS):通过脚本不断刷新页面、发送请求,造成服务器压力。
三、XSS 防御方法
| 防御方法 | 技术实现 | 工具/库 | 适用场景 |
|---|---|---|---|
| 输入过滤 | 正则表达式、Bean Validation | Hibernate Validator | 用户输入校验 |
| 输出转义 | 上下文相关转义 | OWASP Java Encoder | 页面显示用户输入 |
| 模板引擎 | 自动转义机制 | Thymeleaf、Freemarker | 页面渲染 |
| Cookie 安全 | 设置 HttpOnly、Secure | 原生 Cookie API | 会话管理 |
1、输入过滤
-
目标:防止用户输入非法字符,从源头上减少
XSS攻击的可能性。 -
实现方式:
-
使用正则表达式对输入内容进行校验。
-
使用
javax.validation注解对字段进行格式限制。
-
-
注意
-
不要使用黑名单,建议使用白名单。
-
对特殊字段(如用户名、邮箱、评论)进行针对性校验。
-
可结合
Hibernate Validator实现自动校验。
-
<dependency>
<groupId>org.owasp.encoder</groupId>
<artifactId>encoder</artifactId>
<version>2.6.1</version>
</dependency>
package com.example.security;
import org.owasp.encoder.Encode;
public class InputSanitizer {
/**
* 使用正则表达式检查输入是否仅包含字母、数字、空格以及一些常见标点符号。
*/
public static boolean isValidInput(String input) {
if (input == null || input.trim().isEmpty()) {
return false;
}
// 允许的字符集:字母、数字、空格及.,!?
return input.matches("[a-zA-Z0-9\\s.,!?]*");
}
/**
* 对输入字符串进行 HTML 转义,防止 XSS 攻击。
*/
public static String sanitizeForHtml(String input) {
if (input == null) {
return "";
}
return Encode.forHtml(input);
}
/**
* 对输入字符串进行 JavaScript 转义。
*/
public static String sanitizeForJavaScript(String input) {
if (input == null) {
return "";
}
return Encode.forJavaScript(input);
}
/**
* 对 URL 参数进行编码。
// 如果用户输入 <script>alert('xss')</script> 作为查询参数,经过 sanitizeForUrl 方法处理后,它将变成 %3Cscript%3Ealert%28%27xss%27%29%3C%2Fscript%3E,这是一个安全的 URL 编码形式,不会触发任何脚本执行。
*/
public static String sanitizeForUrl(String input) {
if (input == null) {
return "";
}
return Encode.forUriComponent(input);
}
}
2、输出转义
-
目标:在将用户输入插入到
HTML页面前进行转义,防止脚本执行。 -
实现方式:使用
OWASP Java Encoder库进行上下文相关的转义。 -
使用场景:
-
显示用户评论、昵称、文章内容等字段前调用
sanitizeHtml() -
JavaScript动态赋值时调用sanitizeJs() -
URL参数拼接前调用sanitizeUrl()
-
<dependency>
<groupId>org.owasp.encoder</groupId>
<artifactId>encoder</artifactId>
<version>2.6.1</version>
</dependency>
import org.owasp.encoder.Encode;
public class XssUtils {
//显示用户评论、昵称、文章内容等字段前调用 `sanitizeHtml()`
public static String sanitizeHtml(String input) {
return Encode.forHtml(input);
}
// `JavaScript` 动态赋值时调用 `sanitizeJs()`
public static String sanitizeJs(String input) {
return Encode.forJavaScript(input);
}
//`URL` 参数拼接前调用 `sanitizeUrl()`
public static String sanitizeUrl(String input) {
return Encode.forUriComponent(input, StandardCharsets.UTF_8, true);
}
}
3、使用模板引擎自动转义(推荐)
-
目标:通过模板引擎自动完成输出转义,减少手动处理错误。
-
实现方式:
-
使用
Thymeleaf(Spring Boot默认模板引擎) -
Thymeleaf默认对${}内容进行HTML转义 -
优势:
-
自动处理
XSS,无需手动调用转义函数 -
避免开发人员遗漏转义步骤
-
与
Spring Boot集成良好
-
<!-- 自动转义,安全 -->
<p th:text="${userInput}">内容</p>
<!-- 禁用转义(慎用) -->
<p th:utext="${userInput}">内容</p>
4、设置 Cookie 安全属性
-
目标:防止
XSS脚本窃取用户Cookie,避免会话劫持。 -
实现方式:在
Java Web应用中设置Cookie属性为HttpOnly和Secure -
注意事项:
-
所有敏感
Cookie都应设置HttpOnly -
Secure表示只在HTTPS下传输,防止中间人攻击
Cookie cookie = new Cookie("JSESSIONID", "123456");
cookie.setHttpOnly(true); // 防止 JS 读取 Cookie
cookie.setSecure(true); // 仅通过 HTTPS 传输
cookie.setPath("/");
response.addCookie(cookie);


