XSS AntiSamy

XSS介绍

XSS:跨站脚本攻击(Cross Site Scripting),为不和 CSS混淆,故将跨站脚本攻击缩写为XSS。XSS是指恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。有点类似于sql注入。

XSS攻击原理:

HTML是一种超文本标记语言,通过将一些字符特殊地对待来区别文本和标记,例如,小于符号(<)被看作是HTML标签的开始,之间的字符是页面的标题等等。当动态页面中插入的内容含有这些特殊字符时,用户浏览器会将其误认为是插入了HTML标签,当这些HTML标签引入了一段JavaScript脚本时,这些脚本程序就将会在用户浏览器中执行。所以,当这些特殊字符不能被动态页面检查或检查出现失误时,就将会产生XSS漏洞。

AntiSamy介绍

AntiSamy是OWASP的一个开源项目,通过对用户输入的 HTML / CSS / JavaScript 等内容进行检验和清理,确保输入符合应用规范。AntiSamy被广泛应用于Web服务对存储型和反射型XSS的防御中。

AntiSamy的maven坐标:

<dependency> <groupId>org.owasp.antisamy</groupId> <artifactId>antisamy</artifactId> <version>1.5.7</version> </dependency>

AntiSamy入门案例

第一步:创建maven工程antiSamy_demo并配置pom.xml文件

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> <relativePath/> </parent> <groupId>cn.itcast</groupId> <artifactId>antiSamy_demo</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.owasp.antisamy</groupId> <artifactId>antisamy</artifactId> <version>1.5.7</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> </project>

第二步:创建application.yml

server: port: 9000

第三步:创建策略文件/resources/antisamy-test.xml,文件内容可以从antisamy的jar包中获取

注:AntiSamy对“恶意代码”的过滤依赖于策略文件。策略文件规定了AntiSamy对各个标签、属性的处理方法,策略文件定义的严格与否,决定了AntiSamy对XSS漏洞的防御效果。在AntiSamy的jar包中,包含了几个常用的策略文件

第四步:创建User实体类

package cn.itcast.entity; import lombok.Data; @Data public class User { private int id; private String name; private int age; }

第五步:创建UserController

package cn.itcast.controller; import cn.itcast.entity.User; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user") public class UserController { @RequestMapping("/save") public String save(User user){ System.out.println("UserController save.... " + user); return user.getName(); } }

第六步:创建/resources/static/index.html页面

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form method="post" action="/user/save"> id:<input type="text" name="id"><br> name:<input type="text" name="name"><br> age:<input type="text" name="age"><br> <input type="submit" value="submit"> </form> </body> </html>

第七步:创建启动类

package cn.itcast; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class AntiSamyApp { public static void main(String[] args) { SpringApplication.run(AntiSamyApp.class,args); } }

此时我们可以启动项目进行访问,但是还没有进行参数的过滤,所以如果我们输入任意参数都可以正常传递到Controller中,这在实际项目中是非常不安全的。为了对我们输入的数据进行过滤清理,需要通过过滤器来实现。

第八步:创建过滤器,用于过滤所有提交到服务器的请求参数

package cn.itcast.filter; import cn.itcast.wrapper.XssRequestWrapper; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; /* *过滤所有提交到服务器的请求参数 */ public class XssFilter implements Filter{ @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)servletRequest; //传入重写后的Request filterChain.doFilter(new XssRequestWrapper(request),servletResponse); } }

注意:通过上面的过滤器可以发现我们并没有在过滤器中直接进行请求参数的过滤清理,而是直接放行了,那么我们还怎么进行请求参数的过滤清理呢?其实过滤清理的工作是在另外一个类XssRequestWrapper中进行的,当上面的过滤器放行时需要调用filterChain.doFilter()方法,此方法需要传入请求Request对象,此时我们可以将当前的request对象进行包装,而XssRequestWrapper就是Request对象的包装类,在过滤器放行时会自动调用包装类的getParameterValues方法,我们可以在包装类的getParameterValues方法中进行统一的请求参数过滤清理。

第九步:创建XssRequestWrapper类

package cn.itcast.wrapper; import org.owasp.validator.html.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; public class XssRequestWrapper extends HttpServletRequestWrapper { /* * 策略文件 需要将要使用的策略文件放到项目资源文件路径下 */ private static String antiSamyPath = XssRequestWrapper.class.getClassLoader() .getResource( "antisamy-test.xml").getFile(); public static Policy policy = null; static { // 指定策略文件 try { policy = Policy.getInstance(antiSamyPath); } catch (PolicyException e) { e.printStackTrace(); } } /** * AntiSamy过滤数据 * @param taintedHTML 需要进行过滤的数据 * @return 返回过滤后的数据 * */ private String xssClean( String taintedHTML){ try{ // 使用AntiSamy进行过滤 AntiSamy antiSamy = new AntiSamy(); CleanResults cr = antiSamy.scan( taintedHTML, policy); taintedHTML = cr.getCleanHTML(); }catch( ScanException e) { e.printStackTrace(); }catch( PolicyException e) { e.printStackTrace(); } return taintedHTML; } public XssRequestWrapper(HttpServletRequest request) { super(request); } @Override public String[] getParameterValues(String name){ String[] values = super.getParameterValues(name); if ( values == null){ return null; } int len = values.length; String[] newArray = new String[len]; for (int j = 0; j < len; j++){ System.out.println("Antisamy过滤清理,清理之前的参数值:" + values[j]); // 过滤清理 newArray[j] = xssClean(values[j]); System.out.println("Antisamy过滤清理,清理之后的参数值:" + newArray[j]); } return newArray; } }

第十步:为了使上面定义的过滤器生效,需要创建配置类,用于初始化过滤器对象

package cn.itcast.config; import cn.itcast.filter.XssFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AntiSamyConfiguration { /** * 配置跨站攻击过滤器 */ @Bean public FilterRegistrationBean filterRegistrationBean() { FilterRegistrationBean filterRegistration = new FilterRegistrationBean(new XssFilter()); filterRegistration.addUrlPatterns("/*"); filterRegistration.setOrder(1); return filterRegistration; } }

启动项目,页面输入非法数据,可以看到非法数据被清理掉了。

注意:当前我们在进行请求参数过滤时只是在包装类的getParameterValues方法中进行了处理,真实项目中可能用户提交的数据在请求头中,也可能用户提交的是json数据,所以如果考虑所有情况,我们可以在包装类中的多个方法中都进行清理处理即可,如下:

package cn.itcast.wrapper; import org.owasp.validator.html.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.util.Map; public class XssRequestWrapper extends HttpServletRequestWrapper { /** * 策略文件 需要将要使用的策略文件放到项目资源文件路径下 * */ private static String antiSamyPath = XssRequestWrapper.class.getClassLoader() .getResource( "antisamy-ebay.xml").getFile(); public static Policy policy = null; static { // 指定策略文件 try { policy = Policy.getInstance(antiSamyPath); } catch (PolicyException e) { e.printStackTrace(); } } /** * AntiSamy过滤数据 * @param taintedHTML 需要进行过滤的数据 * @return 返回过滤后的数据 * */ private String xssClean( String taintedHTML){ try{ // 使用AntiSamy进行过滤 AntiSamy antiSamy = new AntiSamy(); CleanResults cr = antiSamy.scan( taintedHTML, policy); taintedHTML = cr.getCleanHTML(); }catch( ScanException e) { e.printStackTrace(); }catch( PolicyException e) { e.printStackTrace(); } return taintedHTML; } public XssRequestWrapper(HttpServletRequest request) { super(request); } @Override public String[] getParameterValues(String name){ String[] values = super.getParameterValues(name); if ( values == null){ return null; } int len = values.length; String[] newArray = new String[len]; for (int j = 0; j < len; j++){ // 过滤清理 newArray[j] = xssClean(values[j]); } return newArray; } @Override public String getParameter(String paramString) { String str = super.getParameter(paramString); if (str == null) { return null; } return xssClean(str); } @Override public String getHeader(String paramString) { String str = super.getHeader(paramString); if (str == null) { return null; } return xssClean(str); } @Override public Map<String, String[]> getParameterMap() { Map<String, String[]> requestMap = super.getParameterMap(); for (Map.Entry<String, String[]> me : requestMap.entrySet()) { String[] values = me.getValue(); for (int i = 0; i < values.length; i++) { values[i] = xssClean(values[i]); } } return requestMap; } }
package com.itheima.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/xss") public class XSSController { @GetMapping("/get") public String get(String text){ return "处理之后的文本内容为:" + text; } }

第三步:创建启动类

package com.itheima; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class XssApplication { public static void main(String[] args) { SpringApplication.run(XssApplication.class,args); } }

启动项目,访问如下地址:

可以看到,如果输入的是普通文本则不做任何处理。如果输入的是特殊标签则被清理掉了。


__EOF__

本文作者飞飞很要强
本文链接https://www.cnblogs.com/LiPengFeiii/p/15646824.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   飞飞很要强  阅读(210)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示