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