Java使用过滤器防止SQL注入XSS脚本注入的实现

作者:踮脚敲代码 时间:2021-09-14 18:17:19 

前几天有个客户在系统上写了一段html语句,打开页面就显示一张炒鸡大的图片,影响美观。后来仔细想想,幸亏注入的仅仅是html语句,知道严重性后,马上开始一番系统安全配置。

一. 定义过滤器


package com.cn.unit.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

/**
* 过滤器
* Created by adonis on 2020/12/12
*/
public class SafeFilter implements Filter{

// 配置信息对象
public FilterConfig filterConfig;

/**
* 初始化
* 与我们编写的Servlet程序一样,Filter的创建和销毁由WEB服务器负责。
* Web应用程序启动时,Web服务器将创建Filter的实例对象,并调用其init方法,读取web.xml配置,
* 完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作。
* Filter对象只会创建一次,init方法也只会执行一次。
* 开发人员通过init方法的参数,可获得代表当前Filter配置信息的FilterConfig对象。
*/
 @Override
 public void init(FilterConfig filterConfig) throws ServletException {
  filterConfig = config;
}

/**
  * 拦截请求
  * 这个方法完成实际的过滤操作。当客户请求访问与过滤器关联的URL的时候,Servlet过滤器将先执行doFilter方法。
  * FilterChain参数用于访问后续过滤器。
  */
 @Override
 public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
   HttpServletRequest httpRequest = (HttpServletRequest) request;
   String enctype = httpRequest.getContentType();
   if(StringUtils.isNotBlank(enctype) && enctype.contains("multipart/form-data")){
    // 上传文件
    CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(
    httpRequest.getSession().getServletContext());
  MultipartHttpServletRequest multipartRequest = commonsMultipartResolver.resolveMultipart(httpRequest);
  XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(multipartRequest);
  chain.doFilter(xssRequest, response);
   }else{
    // 普通表单和Ajax
    XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
    chain.doFilter(xssRequest, response);
   }
 }

/**
  * 销毁
  * Filter对象创建后会驻留在内存,当Web应用移除或服务器停止时才销毁。在Web容器卸载Filter对象之前被调用。
  * 该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。
  */
 @Override
 public void destroy() {
  this.filterConfig = null;
}

}

二. 过滤包装器,实现参数值过滤


package com.cn.unit.filter;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
* 用户请求包装类
* Created by adonis on 2020/12/12
*/
public class SafeHttpServletRequestWrapper extends HttpServletRequestWrapper{

public SafeHttpServletRequestWrapper(HttpServletRequest request) {
   super(request);
 }

@Override
 public String getParameter(String name) {
   String value = super.getParameter(name);
   if (value != null) {
     value = xssEncode(value);
   }
   return value;
 }
 @Override
 public String[] getParameterValues(String name) {
   String[] value = super.getParameterValues(name);
   if(value != null){
     for (int i = 0; i < value.length; i++) {
       value[i] = xssEncode(value[i]);
     }
   }
   return value;
 }
@Override
 public Map getParameterMap() {
   return super.getParameterMap();
 }

/**
* 请求头不过滤
*/
 @Override
 public String getHeader(String name) {
  return super.getHeader(name);
 }

/**
  * 将容易引起注入的关键字的半角字符直接替换成全角字符
  * @param value 过滤前的值
  * @return 过滤后的值
  */
 private static String xssEncode(String value) {
   if (value == null || value.isEmpty()) {
     return value;
   }
   // 防SQL注入转义
value = StringEscapeUtils.escapeSql(value);

// HTML防注入,个人建议使用第三种
   // 1.防HTML注入转义(HtmlUtils工具类,汉字不转义,双引号转义,存在JSON封装需要反转义)
   value = HtmlUtils.htmlEscape(value);
   /*
   // 2.防HTML注入转义(StringEscapeUtils工具类,汉字也转义,取出时需要反转义)
   // value = StringEscapeUtils.escapeHtml(value);
   // 3.字符串替换法(通过各种循环替换字符串测试,最终还是replace替换效果最佳)
   value = value.replaceAll("<", "<");
   value = value.replaceAll(">", ">");
   value = value.replaceAll("'", "'");
   value = value.replaceAll(";", "﹔");
   value = value.replaceAll("&", "&");
   value = value.replaceAll("%", "﹪");
   value = value.replaceAll("#", "#");
   value = value.replaceAll("select", "seleᴄt");// "c"→"ᴄ"
   value = value.replaceAll("truncate", "trunᴄate");// "c"→"ᴄ"
   value = value.replaceAll("exec", "exeᴄ");// "c"→"ᴄ"
   value = value.replaceAll("join", "jᴏin");// "o"→"ᴏ"
   value = value.replaceAll("union", "uniᴏn");// "o"→"ᴏ"
   value = value.replaceAll("drop", "drᴏp");// "o"→"ᴏ"
   value = value.replaceAll("count", "cᴏunt");// "o"→"ᴏ"
   value = value.replaceAll("insert", "ins℮rt");// "e"→"℮"
   value = value.replaceAll("update", "updat℮");// "e"→"℮"
   value = value.replaceAll("delete", "delet℮");// "e"→"℮"

value = value.replaceAll("script", "sᴄript");// "c"→"ᴄ"
   value = value.replaceAll("cookie", "cᴏᴏkie");// "o"→"ᴏ"
   value = value.replaceAll("iframe", "ifram℮");// "e"→"℮"
   value = value.replaceAll("onmouseover", "onmouseov℮r");// "e"→"℮"
   value = value.replaceAll("onmousemove", "onmousemov℮");// "e"→"℮"*/
   return value;
 }
}

三. 配置web.xml添加过滤器


<!-- 配置过滤器防止SQL注入XSS注入 -->
<filter>
 <filter-name>XssSqlFilter</filter-name>
 <filter-class>com.cn.unit.filter.SafeFilter</filter-class>
</filter>
<filter-mapping>
 <filter-name>XssSqlFilter</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>

配置各节点简单介绍:

节点名介绍
<filter>指定一个过滤器
<filter-name>用于为过滤器指定一个名字,该元素的内容不能为空
<filter-class>指定过滤器的完整的限定类名
<init-param>为过滤器指定初始化参数。在过滤器中,可以使用FilterConfig接口对象来访问初始化参数
<param-name><init-param>的子元素,指定参数的名字
<param-value><init-param>的子元素,指定参数的值
<filter-mapping>设置一个Filter所负责拦截的资源。可通过Servlet名称或资源访问的请求路径指定
<filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字
<url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)
<servlet-name>指定过滤器所拦截的Servlet名称
<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,默认REQUEST

四. 静态资源跳过过滤

在实际开发的过程中,js、css等静态资源也进行过滤,消耗服务器性能,因此把一些不必要过滤的直接跳过过滤器,实现如下:

4.1 在web.xml配置文件中添加参数,保存静态资源所在的路径


<init-param>
<param-name>excludeFilter</param-name><!-- 静态资源不进行过滤,如js、css文件 -->
<param-value>/document/;/ligentres/</param-value>
</init-param>

如图:

Java使用过滤器防止SQL注入XSS脚本注入的实现

4.2 过滤器初始化方法,读取静态资源所在的路径


public FilterConfig filterConfig;
public String[] excludeFilterArray;
@Override
public void init(FilterConfig config) throws ServletException {
filterConfig = config;
 // 读取web配置文件中的静态资源所在路径
String excludeFilter = filterConfig.getInitParameter("excludeFilter");
excludeFilterArray = excludeFilter.split(";");
}

4.3 过滤器拦截请求,若是静态资源所在的路径直接跳过过滤器


@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
 HttpServletRequest httpRequest = (HttpServletRequest) request;
 String uri = httpRequest.getRequestURI();
 // 静态资源直接跳过,不进行过滤
 if(uri==null||this.isContains(uri, excludeFilterArray)) {
  chain.doFilter(request, response);
  return;
 }
 ......
}

// 判断数组是否包含某一元素
public boolean isContains(String uri, String[] regx) {
 boolean result = false;
 for (int i = 0; i < regx.length; i++) {
  if (uri.indexOf(regx[i]) != -1) {
  return true;
  }
 }
 return result;
}

五. 大功告成

借鉴前人的经验,一开始测试的时候发现,普通的表单提交和ajax提交可以过滤其参数,但上传文件时就无法进入过滤了。

后来经过研究,用于处理文件上传的 MultipartResolver ,当收到请求时,DispatcherServlet 的 checkMultipart() 方法会调用 MultipartResolver 的 isMultipart() 方法判断请求中是否包含文件。如果请求数据中包含文件,则调用 MultipartResolver 的 resolveMultipart() 方法对请求的数据进行解析,然后将文件数据解析成 MultipartFile 并封装在 MultipartHttpServletRequest 对象中,最后传递给 Controller。因此我们只需要在定义过滤器时,先获取请求头判断是否为文件上传,若是再对数据进行解析便可。

来源:https://blog.csdn.net/ii950606/article/details/111323906

标签:Java,过滤器,防止SQL注入
0
投稿

猜你喜欢

  • JAVA提高第八篇 动态代理技术

    2023-07-19 07:13:12
  • Java DecimalFormat 保留小数位及四舍五入的陷阱介绍

    2023-11-09 04:49:33
  • 通过源码角度看看AccessibilityService

    2023-07-25 09:31:43
  • C语言时间函数之strftime()详解

    2023-06-26 02:42:32
  • MyBatis映射文件resultMap元素中使用多个association的方法

    2023-11-29 06:53:51
  • Android应用开发SharedPreferences存储数据的使用方法

    2023-06-23 16:02:47
  • Spring JPA联表查询之注解属性详解

    2021-11-04 14:19:04
  • Android自定义Banner轮播效果

    2023-08-05 23:34:06
  • ShardingSphere jdbc集成多数据源的实现步骤

    2023-11-25 07:54:56
  • SpringBoot依赖管理的源码解析

    2022-10-29 23:37:14
  • java快速生成数据库文档详情

    2023-11-10 05:25:20
  • 教你开发脚手架集成Spring Boot Actuator监控的详细过程

    2021-11-19 03:27:39
  • 详解JAVA流程控制语句

    2023-11-05 02:27:09
  • java 抛出异常处理的方法

    2023-05-12 21:55:54
  • java多线程Thread的实现方法代码详解

    2022-01-03 01:02:28
  • Java环境配置原理全面解析

    2023-11-23 07:56:48
  • Java泛型类与泛型方法的定义详解

    2023-11-25 01:29:22
  • 详谈Java中net.sf.json包关于JSON与对象互转的坑

    2023-03-02 12:38:31
  • springboot 使用poi进行数据的导出过程详解

    2022-12-01 07:23:31
  • Spring Boot支持Crontab任务改造的方法

    2023-08-08 20:20:24
  • asp之家 软件编程 m.aspxhome.com