赞
踩
pd-tools-xxs
pd-tools-xxs
模块定位为防跨站脚本攻击(XSS),通过对用户在页面输入的HTML / CSS / JavaScript等内容进行校验和清理,确保输入内容符合应用规范,保障系统的安全。
XSS:跨站脚本攻击(Cross Site Scripting
),为不和CSS混淆,故将跨站脚本攻击缩写为XSS。XSS是指恶意攻击者往web页面里插入恶意Script
代码,当用户浏览该页时,嵌入其中web里面的Script
代码会被执行,从而达到恶意攻击用户的目的。有点类似于sql注入。
XSS攻击原理:
HTML
是一种超文本标记语言,通过将一些字符特殊地对待来区别文本和标记,例如,小于符号<
被看作是HTML标签的开始,<title>
与</title>
之间的字符是页面的标题等等。当动态页面中插入的内容含有这些特殊字符时,用户浏览器会将其误认为是插入了HTML
标签,当这些HTML
标签引入了一段JavaScript
脚本时,这些脚本程序就将会在用户浏览器中执行。所以,当这些特殊字符不能被动态页面检查或检查出现失误时,就将会产生XSS
漏洞。
AnitSamy
介绍AnitSamy
是OWASP的一个开源项目,通过对用户输入的 HTML / CSS / JavaScript等内容进行校验和清理,确保输入符合应用规范。AnitSamy
被广泛应用于web服务对存储型和反射型XSS的防御中。
AnitSamy
的maven坐标:
<dependency>
<groupId>org.owasp.antisamy</groupId>
<artifactId>antisamy</artifactId>
<version>1.5.7</version>
</dependency>
AnitSamy
入门案例第一步:创建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>com.xbmu</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 com.xbmu.entity;
import lombok.Data;
@Data
public class User {
private int id;
private String name;
private int age;
}
第五步:创建UserController
package com.xbmu.controller;
import com.xbmu.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 com.xbmu;
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 com.xbmu.filter; import com.xbmu.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 com.xbmu.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 com.xbmu.config; import com.xbmu.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 com.xbmu.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-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++){ // 过滤清理 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; } }
pd-tools-xss
使用pd-tools-xss
的实现和我们上面的入门案例是一致的,底层也是基于AntiSamy
对输入参数进行检验和清理,确保输入符合应用规范。为了方便使用,pd-tools-xss
已经定义为了starter,其他应用只需要导入其maven坐标,不需要额外进行任何配置就可以使用。
具体使用过程:
第一步:创建maven工程并配置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>com.xbmu</groupId> <artifactId>myXssApp</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>com.itheima</groupId> <artifactId>pd-tools-xss</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project>
第二步:创建XSSController
package com.xbmu.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.xbmu;
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);
}
}
启动项目,访问如下地址:
可以看到,如果输入的是普通文本则不做任何处理。如果输入的是特殊标签则被清理掉了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。