防止網站遭受惡意腳本攻擊


import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Set;

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


/**
 * @date
 * @describe request信息封裝類,用於判斷、處理request請求中特殊字符
 */
public class XSSHttpRequestWrapper extends HttpServletRequestWrapper {
    
    /**
     * 封裝http請求
     * @param request
     */
    public XSSHttpRequestWrapper(HttpServletRequest request) {
        super(request);
    }
    
    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        // 若開啓特殊字符替換,對特殊字符進行替換
        if(XSSSecurityConfig.REPLACE){
            XSSSecurityManager.securityReplace(name);
        }
        return value;
    }

    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        // 若開啓特殊字符替換,對特殊字符進行替換
        if(XSSSecurityConfig.REPLACE){
            XSSSecurityManager.securityReplace(name);
        }
        return value;
    }

    /**
     * 沒有違規的數據,就返回false;
     *
     * @return
     */
    @SuppressWarnings("unchecked")
    private boolean checkHeader(){
        Enumeration<String> headerParams = this.getHeaderNames();
        while(headerParams.hasMoreElements()){
            String headerName = headerParams.nextElement();
            String headerValue = this.getHeader(headerName);
            if(XSSSecurityManager.matches(headerValue)){
                return true;
            }
        }
        return false;
    }
    
    /**
     * 沒有違規的數據,就返回false;
     *
     * @return
     */
    @SuppressWarnings("unchecked")
    private boolean checkParameter(){
        Map<String,Object> submitParams = this.getParameterMap();
        Set<String> submitNames = submitParams.keySet();
        for(String submitName : submitNames){
            Object submitValues = submitParams.get(submitName);
            if(submitValues instanceof String){
                if(XSSSecurityManager.matches((String)submitValues)){
                    return true;
                }
            }else if(submitValues instanceof String[]){
                for(String submitValue : (String[])submitValues){
                    if(XSSSecurityManager.matches((String)submitValue)){
                        return true;
                    }
                }
            }
        }
        return false;
    }
    
   
    /**
     * 沒有違規的數據,就返回false;
     * 若存在違規數據,根據配置信息判斷是否跳轉到錯誤頁面
     * @param response
     * @return
     * @throws IOException
     * @throws ServletException
     */
    public boolean validateParameter(HttpServletResponse response) throws ServletException, IOException{
        // 開始header校驗,對header信息進行校驗
        if(XSSSecurityConfig.IS_CHECK_HEADER){
            if(this.checkHeader()){
                return true;
            }
        }
        // 開始parameter校驗,對parameter信息進行校驗
        if(XSSSecurityConfig.IS_CHECK_PARAMETER){
            if(this.checkParameter()){
                return true;
            }
        }
        return false;
    }
    
}




/**
 * @date
 * @describe
 */
public class XSSSecurityCon {

    /**
     * 配置文件標籤 isCheckHeader
     */
    public static String IS_CHECK_HEADER = "isCheckHeader";

    /**
     * 配置文件標籤 isCheckParameter
     */
    public static String IS_CHECK_PARAMETER = "isCheckParameter";

    /**
     * 配置文件標籤 isLog
     */
    public static String IS_LOG = "isLog";

    /**
     * 配置文件標籤 isChain
     */
    public static String IS_CHAIN = "isChain";

    /**
     * 配置文件標籤 replace
     */
    public static String REPLACE = "replace";

    /**
     * 配置文件標籤 regexList
     */
    public static String REGEX_LIST = "regexList";

    /**
     * 替換非法字符的字符串
     */
    public static String REPLACEMENT = "";

    /**
     * FILTER_ERROR_PAGE:過濾後錯誤頁面
     */
    public static String FILTER_ERROR_PAGE = "filterErrorPage";

}




/**
 * 安全過濾配置信息類
 */
public class XSSSecurityConfig {
    
    /**
     * CHECK_HEADER:是否開啓header校驗
     */
    public static boolean IS_CHECK_HEADER;
    
    /**
     * CHECK_PARAMETER:是否開啓parameter校驗
     */
    public static boolean IS_CHECK_PARAMETER;
    
    /**
     * IS_LOG:是否記錄日誌
     */
    public static boolean IS_LOG;
    
    /**
     * IS_LOG:是否中斷操作
     */
    public static boolean IS_CHAIN;
    
    /**
     * REPLACE:是否開啓替換
     */
    public static boolean REPLACE;
    
    /**
     * FILTER_ERROR_PAGE:過濾後錯誤頁面
     */
    public static String FILTER_ERROR_PAGE;
    

}



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 javax.servlet.http.HttpServletResponse;
/**
 * @date
 * @describe 安全信息審覈類
 */
public class XSSSecurityFilter implements Filter{
    public XSSSecurityFilter() {
        // TODO Auto-generated constructor stub
    }
    
    /**
     * 銷燬操作
     */
    public void destroy() {
        //System.out.println("XSSSecurityFilter destroy() begin");
        XSSSecurityManager.destroy();
        //System.out.println("XSSSecurityFilter destroy() end");
    }

    /**
     * 安全審覈
     * 讀取配置信息
     */
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        // 判斷是否使用HTTP
        checkRequestResponse(request, response);
        // 轉型
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        // http信息封裝類
        XSSHttpRequestWrapper xssRequest = new XSSHttpRequestWrapper(httpRequest);
        
        // 對request信息進行封裝並進行校驗工作,若校驗失敗(含非法字符),根據配置信息進行日誌記錄和請求中斷處理
        if(xssRequest.validateParameter(httpResponse)){
            if(XSSSecurityConfig.IS_LOG){
                // 記錄攻擊訪問日誌
                // 可使用數據庫、日誌、文件等方式
            }
            if(XSSSecurityConfig.IS_CHAIN){
                httpRequest.getRequestDispatcher(XSSSecurityConfig.FILTER_ERROR_PAGE).forward( httpRequest, httpResponse);
                return;
            }
        }
        chain.doFilter(xssRequest, response);
    }

    /**
     * 初始化操作
     */
    public void init(FilterConfig filterConfig) throws ServletException {
        //System.out.println("-------init()-------");
        XSSSecurityManager.init(filterConfig);
    }

    /**
     * 判斷Request ,Response 類型
     * @param request
     *            ServletRequest
     * @param response
     *            ServletResponse
     * @throws ServletException
     */
    private void checkRequestResponse(ServletRequest request,
            ServletResponse response) throws ServletException {
        if (!(request instanceof HttpServletRequest)) {
            throw new ServletException("Can only process HttpServletRequest");

        }
        if (!(response instanceof HttpServletResponse)) {
            throw new ServletException("Can only process HttpServletResponse");
        }
    }
}



import java.util.Iterator;
import java.util.regex.Pattern;

import javax.servlet.FilterConfig;

import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * @date
 * @describe 安全過濾配置管理類,由XSSSecurityManger修改
 */
public class XSSSecurityManager {
    
    //private static Logger logger = Logger.getLogger(XSSSecurityManager.class);
    
    /**
     * REGEX:校驗正則表達式
     */
    public static String REGEX;
    
     /**
     * 特殊字符匹配
     */
    private static Pattern XSS_PATTERN ;
    
    
    private XSSSecurityManager(){
        //不可被實例化
    }
    
    public static void init(FilterConfig config){
//        System.out.println("XSSSecurityManager init(FilterConfig config) begin");
        //初始化過濾配置文件
        String xssPath = config.getServletContext().getRealPath("/")
                + config.getInitParameter("securityconfig");
        
        //String xssPath="F:\\site\\xsssecurity\\WEB-INF\\classes\\xss_security_config.xml";
        
//        System.out.println("路徑:"+xssPath);
        // 初始化安全過濾配置
        try {
            if(initConfig(xssPath)){
                // 生成匹配器
                XSS_PATTERN = Pattern.compile(REGEX);
            }
        } catch (DocumentException e) {
            //logger.error("安全過濾配置文件xss_security_config.xml加載異常",e);
//            System.out.println("安全過濾配置文件xss_security_config.xml加載異常");
        }
        //logger.info("XSSSecurityManager init(FilterConfig config) end");
//        System.out.println("XSSSecurityManager init(FilterConfig config) end");
    }
    
    /**
     * 讀取安全審覈配置文件xss_security_config.xml
     * 設置XSSSecurityConfig配置信息
     * @param path 配置文件地址 eg C:/apache-tomcat-6.0.33/webapps/security_filter/WebRoot/config/xss/xss_security_config.xml
     * @return
     * @throws DocumentException
     */
    @SuppressWarnings("unchecked")
    public static boolean initConfig(String path) throws DocumentException {
//        logger.info("XSSSecurityManager.initConfig(String path) begin");
//        System.out.println("XSSSecurityManager.initConfig(String path) begin");
        Element superElement = new SAXReader().read(path).getRootElement();
        XSSSecurityConfig.IS_CHECK_HEADER = new Boolean(getEleValue(superElement,XSSSecurityCon.IS_CHECK_HEADER));
        XSSSecurityConfig.IS_CHECK_PARAMETER = new Boolean(getEleValue(superElement,XSSSecurityCon.IS_CHECK_PARAMETER));
        XSSSecurityConfig.IS_LOG = new Boolean(getEleValue(superElement,XSSSecurityCon.IS_LOG));
        XSSSecurityConfig.IS_CHAIN = new Boolean(getEleValue(superElement,XSSSecurityCon.IS_CHAIN));
        XSSSecurityConfig.REPLACE = new Boolean(getEleValue(superElement,XSSSecurityCon.REPLACE));
        XSSSecurityConfig.FILTER_ERROR_PAGE = getEleValue(superElement,XSSSecurityCon.FILTER_ERROR_PAGE);

        Element regexEle = superElement.element(XSSSecurityCon.REGEX_LIST);
        
        if(regexEle != null){
            Iterator<Element> regexIt = regexEle.elementIterator();
            StringBuffer tempStr = new StringBuffer("^");
            //xml的cdata標籤傳輸數據時,會默認在\前加\,需要將\\替換爲\
            while(regexIt.hasNext()){
                Element regex = (Element)regexIt.next();
                String tmp = regex.getText();
                tmp = tmp.replaceAll("\\\\\\\\", "\\\\");
                tempStr.append(tmp);
                tempStr.append("|");
            }
            if(tempStr.charAt(tempStr.length()-1)=='|'){
                REGEX= tempStr.substring(0, tempStr.length()-1)+"$";
                //logger.info("安全匹配規則"+REGEX);
//                System.out.println("安全匹配規則"+REGEX);
            }else{
                //logger.error("安全過濾配置文件加載失敗:正則表達式異常 "+tempStr.toString());
//                System.out.println("安全過濾配置文件加載失敗:正則表達式異常 ");
                return false;
            }
        }else{
            //logger.error("安全過濾配置文件中沒有 "+XSSSecurityCon.REGEX_LIST+" 屬性");
//            System.out.println("安全過濾配置文件中沒有 "+XSSSecurityCon.REGEX_LIST+" 屬性");
            return false;
        }
        //logger.info("XSSSecurityManager.initConfig(String path) end");
//        System.out.println("XSSSecurityManager.initConfig(String path) end");
        return true;

    }
    
    /**
     * 從目標element中獲取指定標籤信息,若找不到該標籤,記錄錯誤日誌
     * @param element 目標節點
     * @param tagName 制定標籤
     * @return
     */
    private static String getEleValue(Element element, String tagName){
        if (isNullStr(element.elementText(tagName))){
            //logger.error("安全過濾配置文件中沒有 "+XSSSecurityCon.REGEX_LIST+" 屬性");
//            System.out.println("安全過濾配置文件中沒有 "+XSSSecurityCon.REGEX_LIST+" 屬性");
        }
        return element.elementText(tagName);
    }
    
    /**
     * 對非法字符進行替換
     * @param text
     * @return
     */
    public static String securityReplace(String text){
//        System.out.println("對非法字符進行替換");
        if(isNullStr(text)){
//            System.out.println("if:---"+text);
            return text;
        }else{
//            System.out.println("else:---"+text.replaceAll(REGEX, XSSSecurityCon.REPLACEMENT));
            return text.replaceAll(REGEX, XSSSecurityCon.REPLACEMENT);
        }
    }
    
    /**
     * 匹配字符是否含特殊字符
     * @param text
     * @return
     */
    public static boolean matches(String text){
//        System.out.println("匹配字符是否含特殊字符");
        if(text==null){
            return false;
        }
        return XSS_PATTERN.matcher(text).matches();
    }
    
    /**
     * 釋放關鍵信息
     */
    public static void destroy(){
//        logger.info("XSSSecurityManager.destroy() begin");
//        System.out.println("XSSSecurityManager.destroy() begin");
        XSS_PATTERN = null;
        REGEX = null;
//        logger.info("XSSSecurityManager.destroy() end");
//        System.out.println("XSSSecurityManager.destroy() end");
    }
    
    /**
     * 判斷是否爲空串,建議放到某個工具類中
     * @param value
     * @return
     */
    public static boolean isNullStr(String value){
        return value == null || value.trim().equals("");
    }
}

xss_security_config.xml

<?xml version="1.0" encoding="UTF-8"?>
<XSSConfig>
    <!-- 是否進行header校驗 -->
    <isCheckHeader>true</isCheckHeader>
    <!-- 是否進行parameter校驗 -->
    <isCheckParameter>true</isCheckParameter>
    <!-- 是否記錄日誌 -->
    <isLog>false</isLog>
    <!-- 是否中斷請求 -->
    <isChain>true</isChain>
    <!-- 是否開啓特殊字符替換 -->
    <replace>true</replace>
    <!-- 是否開啓特殊url校驗 -->
    <isCheckUrl>true</isCheckUrl>
    <!-- 過濾後錯誤頁面,是否中斷請求爲真時有效 -->
    <filterErrorPage>/filtererror.jsp</filterErrorPage>
    <regexList>
        <!-- 匹配含有字符: alert( ) -->
        <regex><![CDATA[.*[A|a][L|l][E|e][R|r][T|t]\\s*\\(.*\\).*]]></regex>
        <!-- 匹配含有字符: window.location = -->
        <regex><![CDATA[.*[W|w][I|i][N|n][D|d][O|o][W|w]\\.[L|l][O|o][C|c][A|a][T|t][I|i][O|o][N|n]\\s*=.*]]></regex>
        <!-- 匹配含有字符:style = x:ex pression ( ) -->
        <regex><![CDATA[.*[S|s][T|t][Y|y][L|l][E|e]\\s*=.*[X|x]:[E|e][X|x].*[P|p][R|r][E|e][S|s]{1,2}[I|i][O|o][N|n]\\s*\\(.*\\).*]]></regex>
        <!-- 匹配含有字符: document.cookie -->
        <regex><![CDATA[.*[D|d][O|o][C|c][U|u][M|m][E|e][N|n][T|t]\\.[C|c][O|o]{2}[K|k][I|i][E|e].*]]></regex>
        <!-- 匹配含有字符: eval( ) -->
        <regex><![CDATA[.*[E|e][V|v][A|a][L|l]\\s*\\(.*\\).*]]></regex>
        <!-- 匹配含有字符: unescape() -->
        <regex><![CDATA[.*[U|u][N|n][E|e][S|s][C|c][A|a][P|p][E|e]\\s*\\(.*\\).*]]></regex>
        <!-- 匹配含有字符: execscript( ) -->
        <regex><![CDATA[.*[E|e][X|x][E|e][C|c][S|s][C|c][R|r][I|i][P|p][T|t]\\s*\\(.*\\).*]]></regex>
        <!-- 匹配含有字符: msgbox( ) -->
        <regex><![CDATA[.*[M|m][S|s][G|g][B|b][O|o][X|x]\\s*\\(.*\\).*]]></regex>
        <!-- 匹配含有字符: confirm( ) -->
        <regex><![CDATA[.*[C|c][O|o][N|n][F|f][I|i][R|r][M|m]\\s*\\(.*\\).*]]></regex>
        <!-- 匹配含有字符: prompt( ) -->
        <regex><![CDATA[.*[P|p][R|r][O|o][M|m][P|p][T|t]\\s*\\(.*\\).*]]></regex>
        <!-- 匹配含有字符: <script> </script> or </script> -->
        <regex><![CDATA[.*<[B|b][O|o][D|d][Y|y].*>.*|.*</[B|b][O|o][D|d][Y|y].*>.*|.*<[S|s][C|c][R|r][I|i][P|p][T|t].*>.*|.*<[S|s][C|c][R|r][I|i][P|p][T|t]>.*</[S|s][C|c][R|r][I|i][P|p][T|t]>.*|.*</[S|s][C|c][R|r][I|i][P|p][T|t]>.*]]></regex>
        <!-- 匹配含有字符: 含有一個符號: "  -->
        <regex><![CDATA[[.&[^\"]]*\"[.&[^\"]]*]]></regex>
        <!-- 匹配含有字符: 含有一個符號: '  -->
        <regex><![CDATA[[.&[^']]*'[.&[^']]*]]></regex>
        <!-- 匹配含有字符:<title></title> -->
        <regex><![CDATA[.*<[T|t][I|i][T|t][L|l][E|e].*>.*|.*</[T|t][I|i][T|t][L|l][E|e]>.*]]></regex>
        <!-- 匹配含有字符: 含有回車換行 和 <script> </script> -->
        <regex><![CDATA[[[.&[^a]]|[|a|\n|\r\n|\r|\u0085|\u2028|\u2029]]*<[S|s][C|c][R|r][I|i][P|p][T|t]>.*</[S|s][C|c][R|r][I|i][P|p][T|t]>[[.&[^a]]|[|a|\n|\r\n|\r|\u0085|\u2028|\u2029]]*]]></regex>
    </regexList>
</XSSConfig>

發佈了109 篇原創文章 · 獲贊 17 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章