当前位置:网站首页>五、品达通用权限系统__pd-tools-xxs(防跨站脚本攻击)
五、品达通用权限系统__pd-tools-xxs(防跨站脚本攻击)
2022-07-25 21:24:00 【上善若水】
一、pd-tools-xxs
pd-tools-xxs模块定位为防跨站脚本攻击(XSS),通过对用户在页面输入的HTML / CSS / JavaScript等内容进行校验和清理,确保输入内容符合应用规范,保障系统的安全。
1.1、XSS介绍
XSS:跨站脚本攻击(Cross Site Scripting),为不和CSS混淆,故将跨站脚本攻击缩写为XSS。XSS是指恶意攻击者往web页面里插入恶意Script代码,当用户浏览该页时,嵌入其中web里面的Script代码会被执行,从而达到恶意攻击用户的目的。有点类似于sql注入。
XSS攻击原理:HTML是一种超文本标记语言,通过将一些字符特殊地对待来区别文本和标记,例如,小于符号<被看作是HTML标签的开始,<title>与</title>之间的字符是页面的标题等等。当动态页面中插入的内容含有这些特殊字符时,用户浏览器会将其误认为是插入了HTML标签,当这些HTML标签引入了一段JavaScript脚本时,这些脚本程序就将会在用户浏览器中执行。所以,当这些特殊字符不能被动态页面检查或检查出现失误时,就将会产生XSS漏洞。
1.2、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>
1.3、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;
}
}

1.4、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);
}
}
启动项目,访问如下地址:

可以看到,如果输入的是普通文本则不做任何处理。如果输入的是特殊标签则被清理掉了。
边栏推荐
- [FAQ] access the HMS core push service, and the server sends messages. Cause analysis and solutions of common error codes
- Reading the pointpillar code of openpcdet -- Part 3: Calculation of loss function
- Autojs learning - Automatic screenshot of the king
- 两数,三数之和
- Autojs learning - file depth search
- When facing complex problems, systematic thinking helps you understand the essence of the problem
- Talk about what's going on with C # backstage GC?
- Autojs learning - realize 3D perspective
- ONEFLOW V0.8.0 officially released
- An interview question combining defer and function in golang
猜你喜欢

Canvas 填充渐变

黑盒(功能)测试基本方法

Jmeter分布式压测

As a test, how to understand thread synchronization and asynchrony

Decompile app

DDD的Go实战

Qixin Jushi cloud spectrum new chapter | Haitai Fangyuan and Sichuan Unicom reach ecological strategic cooperation

Per capita Swiss number series, Swiss number 4 generation JS reverse analysis

人脸与关键点检测:YOLO5Face实战

工作面试总遇秒杀? 看了京东 T8 大咖私藏的秒杀系统笔记, 已献出膝盖
随机推荐
如何自动生成短链?如何在线批量生成带UTM参数的链接?
How to solve the problem of high concurrency and large traffic with PHP
Miscellaneous notes -- a hodgepodge
Programmer's Guide to health quenching 5: introduction to sports Basics
ZigBee IOT development platform (Industrial IOT)
Opencv learning Fourier transform experience and line direction Fourier transform code
Rent two or three things
人脸与关键点检测:YOLO5Face实战
Byte side: can TCP and UDP use the same port?
Temperature and humidity environment monitoring system based on stm32
An interview question about concurrent reading and writing of map in golang
Niuke-top101-bm38
As a test, how to understand thread synchronization and asynchrony
Please give an example of how to optimize MySQL index (sqlserver index optimization)
[FAQ] access the HMS core push service, and the server sends messages. Cause analysis and solutions of common error codes
Mysql8.0 MHA to achieve high availability "MHA"
[FAQ] access the HMS core push service, and the server sends messages. Cause analysis and solutions of common error codes
Stm3 (cubeide) lighting experiment
When MySQL imports data, it has been changed to CSV utf8 file and the file name is English. Why does it still fail to import
Reading the pointpillar code of openpcdet -- Part 3: Calculation of loss function