企业网站建设与优化,一个成功的网站要具备哪些方面,深圳网站制作哪家价格便宜,中国建筑装饰网排行在Spring Boot中#xff0c;我们可以使用注解的方式来进行XSS防御。注解是一种轻量级的防御手段#xff0c;它可以在方法或字段级别对输入进行校验#xff0c;从而防止XSS攻击。
而想对全局的请求都进行XSS防御可以使用servlet中的过滤器或者spring mvc中的拦截器#xff…在Spring Boot中我们可以使用注解的方式来进行XSS防御。注解是一种轻量级的防御手段它可以在方法或字段级别对输入进行校验从而防止XSS攻击。
而想对全局的请求都进行XSS防御可以使用servlet中的过滤器或者spring mvc中的拦截器这里使用servlet中的过滤器进行演示。
引入相关依赖
maven依赖
!--JSR-303/JSR-380用于验证的注解 --
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-validation/artifactIdversion2.6.7/version
/dependency如果是使用grade引入依赖
implementation org.springframework.boot:spring-boot-starter-validation:2.6.7修改配置文件
xss:enabled: trueexcludeUrlList:- /xss/local/test定义配置文件对应的属性类
package com.morris.spring.boot.module.xss;import lombok.Data;import java.util.List;Data
public class XssFilterProperties {/*** 是否启用XSS过滤。*/private boolean enabled true;/*** 需要排除的URL模式这些URL不会进行XSS过滤。*/private ListString excludeUrlList;
}注入XSS配置类
package com.morris.spring.boot.module.xss;import lombok.Data;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;import javax.servlet.DispatcherType;Data
Configuration
public class XssFilterConfig {ConfigurationProperties(prefix xss)Beanpublic XssFilterProperties xssFilterProperties() {return new XssFilterProperties();}/*** 注册XSS过滤器。** return FilterRegistrationBean 用于注册过滤器的bean。*/Beanpublic FilterRegistrationBeanXssFilter xssFilterRegistration(XssFilterProperties xssFilterProperties) {FilterRegistrationBeanXssFilter registrationBean new FilterRegistrationBean();// 设置过滤器的分发类型为请求类型registrationBean.setDispatcherTypes(DispatcherType.REQUEST);// 创建XssFilter的实例registrationBean.setFilter(new XssFilter(xssFilterProperties));// 添加过滤器需要拦截的URL模式这里拦截所有请求registrationBean.addUrlPatterns(/*);// 设置过滤器的名称registrationBean.setName(XssFilter);// 设置过滤器的执行顺序数值越小优先级越高registrationBean.setOrder(9999);return registrationBean;}Beanpublic HttpMessageConverters xssHttpMessageConverters() {XSSMappingJackson2HttpMessageConverter xssMappingJackson2HttpMessageConverter new XSSMappingJackson2HttpMessageConverter();HttpMessageConverter converter xssMappingJackson2HttpMessageConverter;return new HttpMessageConverters(converter);}}XssFilter过滤器
XssFilter过滤器会将所有需要进行防御的请求包装为XssWrapper。
package com.morris.spring.boot.module.xss;import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;Slf4j
public class XssFilter implements Filter {private final XssFilterProperties xssFilterProperties;public XssFilter(XssFilterProperties xssFilterProperties) {this.xssFilterProperties xssFilterProperties;}/*** 执行过滤逻辑如果当前请求不在排除列表中则通过XSS过滤器包装请求。** param request HTTP请求对象。* param response HTTP响应对象。* param chain 过滤器链对象用于继续或中断请求处理。* throws IOException 如果处理过程中出现I/O错误。* throws ServletException 如果处理过程中出现Servlet相关错误。*/Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest req (HttpServletRequest) request;HttpServletResponse resp (HttpServletResponse) response;//如果该访问接口在排除列表里面则不拦截if (isExcludeUrl(req.getServletPath())) {chain.doFilter(request, response);return;}log.info(uri:{}, req.getRequestURI());// xss 过滤chain.doFilter(new XssWrapper(req), resp);}/*** 判断当前请求的URL是否应该被排除在XSS过滤之外。** param urlPath 请求的URL路径。* return 如果请求应该被排除则返回true否则返回false。*/private boolean isExcludeUrl(String urlPath) {if (!xssFilterProperties.isEnabled()) {//如果xss开关关闭了则所有url都不拦截return true;}if(CollectionUtils.isEmpty(xssFilterProperties.getExcludeUrlList())) {return false;}for (String pattern : xssFilterProperties.getExcludeUrlList()) {Pattern p Pattern.compile(^ pattern);Matcher m p.matcher(urlPath);if (m.find()) {return true;}}return false;}
}XssWrapper过滤get请求和请求头
XssWrapper会过滤get请求和请求头中的非法字符。
package com.morris.spring.boot.module.xss;import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;Slf4j
public class XssWrapper extends HttpServletRequestWrapper {public XssWrapper(HttpServletRequest request) {super(request);}/*** 对数组参数进行特殊字符过滤*/Overridepublic String[] getParameterValues(String name) {String[] values super.getParameterValues(name);if (values null) {return null;}int count values.length;String[] encodedValues new String[count];for (int i 0; i count; i) {encodedValues[i] XssUtil.clean(values[i]);}return encodedValues;}/*** 对参数中特殊字符进行过滤*/Overridepublic String getParameter(String name) {String value super.getParameter(name);if (StringUtils.isBlank(value)) {return value;}return XssUtil.clean(value);}/*** 获取attribute,特殊字符过滤*/Overridepublic Object getAttribute(String name) {Object value super.getAttribute(name);if (value instanceof String StringUtils.isNotBlank((String) value)) {return XssUtil.clean((String) value);}return value;}/*** 对请求头部进行特殊字符过滤*/Overridepublic String getHeader(String name) {String value super.getHeader(name);if (StringUtils.isBlank(value)) {return value;}return XssUtil.clean(value);}
}MessageConverter过滤post请求
package com.morris.spring.boot.module.xss;import com.fasterxml.jackson.databind.JavaType;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;import java.io.IOException;
import java.lang.reflect.Type;/*** 在读取和写入JSON数据时特殊字符避免xss攻击的消息解析器**/
public class XSSMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {/*** 从HTTP输入消息中读取对象同时应用XSS防护。* * param type 类型令牌表示要读取的对象类型。* param contextClass 上下文类提供类型解析的上下文信息。* param inputMessage HTTP输入消息包含要读取的JSON数据。* return 从输入消息中解析出的对象经过XSS防护处理。* throws IOException 如果发生I/O错误。* throws HttpMessageNotReadableException 如果消息无法读取。*/Overridepublic Object read(Type type, Class contextClass,HttpInputMessage inputMessage) throws IOException,HttpMessageNotReadableException {JavaType javaType getJavaType(type, contextClass);Object obj readJavaType(javaType, inputMessage);//得到请求jsonString json super.getObjectMapper().writeValueAsString(obj);//过滤特殊字符String result XssUtil.clean(json);Object resultObj super.getObjectMapper().readValue(result, javaType);return resultObj;}/*** 从HTTP输入消息中读取指定Java类型的对象内部使用。* * param javaType 要读取的对象的Java类型。* param inputMessage HTTP输入消息包含要读取的JSON数据。* return 从输入消息中解析出的对象。* throws IOException 如果发生I/O错误。* throws HttpMessageNotReadableException 如果消息无法读取。*/private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) {try {return super.getObjectMapper().readValue(inputMessage.getBody(), javaType);} catch (IOException ex) {throw new HttpMessageNotReadableException(Could not read JSON: ex.getMessage(), ex);}}/*** 将对象写入HTTP输出消息同时应用XSS防护。* * param object 要写入的对象。* param outputMessage HTTP输出消息对象将被序列化为JSON并写入此消息。* throws IOException 如果发生I/O错误。* throws HttpMessageNotWritableException 如果消息无法写入。*/Overrideprotected void writeInternal(Object object, HttpOutputMessage outputMessage)throws IOException, HttpMessageNotWritableException {//得到要输出的jsonString json super.getObjectMapper().writeValueAsString(object);//过滤特殊字符String result XssUtil.clean(json);// 输出outputMessage.getBody().write(result.getBytes());}
}Xss过滤工具类
package com.morris.spring.boot.module.xss;import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.safety.Whitelist;/*** XSS过滤工具类使用Jsoup库对输入的字符串进行XSS攻击防护*/
public class XssUtil {/*** 使用jsoup自带的relaxed白名单*/private static final Whitelist WHITE_LIST Whitelist.relaxed();/*** 定义输出设置关闭prettyPrintprettyPrintfalse目的是避免在清理过程中对代码进行格式化* 从而保持输入和输出内容的一致性。*/private static final Document.OutputSettings OUTPUT_SETTINGS new Document.OutputSettings().prettyPrint(false);/*初始化白名单策略允许所有标签拥有style属性。这是因为在富文本编辑中样式通常通过style属性来定义需要确保这些样式能够被保留。*/static {// 富文本编辑时一些样式是使用 style 来进行实现的// 比如红色字体 stylecolor:red;// 所以需要给所有标签添加 style 属性WHITE_LIST.addAttributes(:all, style);}/*** 清理输入的字符串移除潜在的XSS攻击代码。** param content 待清理的字符串通常是用户输入的HTML内容。* return 清理后的字符串保证不包含XSS攻击代码。*/public static String clean(String content) {// 使用定义好的白名单策略和输出设置清理输入的字符串return Jsoup.clean(content, , WHITE_LIST, OUTPUT_SETTINGS);}
}get请求测试
package com.morris.spring.boot.module.xss;import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** Xss2防御get请求*/
RestController
RequestMapping(/xss/global)
Validated
public class XssGlobalGetController {/*** 使用注解拦截get请求中的xss在方法参数前面加上Xss注意类上面要加上Validated注解** param userAccount 请求参数* return 请求参数*/GetMapping(/test)public String test(String userAccount) {return userAccount;}}发送get请求http://localhost:8888/xss/global/test?userAccountdemoData
返回结果demoData
post请求测试
package com.morris.spring.boot.module.xss;import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** Xss全局防御post请求*/
RestController
RequestMapping(/xss/global)
public class XssGlobalPostController {/*** 使用注解拦截POST请求中的xss在实体类需要拦截xss的属性上面加上Xss或者Validated注解** param userGlobalLoginPojo 实体类* return 实体类*/PostMapping(/test)public UserGlobalLoginPojo test(RequestBody UserGlobalLoginPojo userGlobalLoginPojo) {return userGlobalLoginPojo;}}发送post请求http://localhost:8888/xss/global/test
请求体
{userAccount: iframe οnlοadalert(0)demoData/iframe
}返回结果
{userAccount: demoData
}