springboot/tomcat使用filter优雅地实现防御xss攻击、sql注入和目录遍历等


springboot/tomcat使用filter实现防御xss攻击、sql注入、目录遍历等

作为一个有经验的Java web开发人员,相信大家都知道拦截器intercept和过滤器filter,他两基本可以实现的功能都差不多,下面简单说一下其区别:

1.filter是servlet的内容,对servlet的扩展都是基于filter完成

2.intercept是spring mvc框架的内容,只能在spring mvc项目中使用

3.spring mvc实现了servlet规范,所有前端请求执行顺序,请求intercept拦截器链》请求filter过滤器链》具体服务》响应filter过滤器链》响应intercept拦截器链

两个注解

@WebFilter(filterName = "securityFilter", urlPatterns = "/*")
@Component

@Component是spring的注解,springboot会扫描此类并添加到sevlet的FilterChain中

@WebFilter主要是提供的容器扫描加载,如tomcat容器,将filter打包放在lib目录下即可,省去web.xml中配置filter和filter-mapping,如下

    <filter>
        <filter-name>ruphyFilter</filter-name>
        <filter-class>
          me.muphy.tomcat.filter.RequestFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>ruphyFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

xss或sql注入防御,就是对前端的不信任,需要对前端的输入做安全校验、过滤和替换,我见过有人写了很多的代码去列举并替换危险的字符串,限制了大量用户输入,却只是看起来安全,治标不治本

要修改过滤请求中的参数,显然不能直接修改原来的ServletRequest对象,首先想到的肯定是(代理)包装器模式,但如何包装呢,虽然包装器需要大量修改的地方只有前端相关的方法,其他大部分都是直接调被包装的方法,但要实现HttpServletRequest接口的方法太多,通过分析源码发现只需要继承HttpServletRequestWrapper这个类即可只复写我们关注的方法,然后调用filterChain.doFilter方法时传入包装类即可

下面我实现了一个很简单但功能强大的安全filter,共参考,代码如下:

package me.muphy.filter;

import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@WebFilter(filterName = "securityFilter", urlPatterns = "/*")
@Component
public class SecurityFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if (servletRequest instanceof HttpServletRequest) {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            filterChain.doFilter(new SecurityHttpServletRequestWrapper(request), servletResponse);
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

    /**
     * 此几行正则表达式 史上最强防御xss攻击、sql注入、目录遍历等,却较少影响用户使用特殊字符和关键字
     */
    public class SecurityHttpServletRequestWrapper extends HttpServletRequestWrapper {

        private Map<String, String> regRep = new HashMap<>();

        public SecurityHttpServletRequestWrapper(HttpServletRequest request) {
            super(request);
            regRep.put("'([^']*)'", "‘$1’");
            regRep.put("`([^`]*)`", "~$1~");
regRep.put("'([^ ]* )", " $1"); regRep.put(
"(\\.\\.[\\\\/]+)+", ""); regRep.put("'(.*--+)", "‘$1"); regRep.put("\\\"([^\\\"]*)\\\"", "“$1”"); regRep.put("\\(([^\\)]*)\\)", "($1)"); regRep.put("<([^>]+)>", "&lt;$1&gt;"); } // 上次直接替换还是会被绕过 这里更新使用while循环替换 private String replace(String val) { if (val != null) { for (String key : regRep.keySet()) { String nval = val; val = val.replaceAll(key, regRep.get(key)); while (!val.equals(nval)) { nval = val; val = val.replaceAll(key, regRep.get(key)); } } } return val; } @Override public String getHeader(String name) { return replace(super.getHeader(name)); } @Override public Cookie[] getCookies() { Cookie[] cookies = super.getCookies(); if (cookies != null) { for (int i = 0; i < cookies.length; i++) { cookies[i].setValue(replace(cookies[i].getValue())); } } return cookies; } @Override public String getQueryString() { return replace(super.getQueryString()); } @Override public String getParameter(String name) { return replace(super.getParameter(name)); } @Override public String[] getParameterValues(String name) { String[] values = super.getParameterValues(name); if (values != null) { for (int i = 0; i < values.length; i++) { values[i] = replace(values[i]); } } return values; } @Override public Map<String, String[]> getParameterMap() { Map<String, String[]> parameterMap = super.getParameterMap(); if (parameterMap != null) { for (String key : parameterMap.keySet()) { String[] values = parameterMap.get(key); if (values != null) { for (int i = 0; i < values.length; i++) { values[i] = replace(values[i]); } } } } return parameterMap; } } }

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM