【漏洞三】跨站點腳本(XSS)攻擊


【漏洞】

跨站點腳本(XSS)攻擊

 

【原因】

跨站點腳本(也稱為xss)是一個漏洞,攻擊者可以發送惡意代碼(通常在(Javascript的形式)給另一個用戶。因為瀏覽器無法知道腳本是否值得信任,所以它將在用戶上下文中執行腳本,從而允許攻擊者訪問任何cookie。

 

【解決】增加敏感腳本過濾器(轉一篇整理較好的實現方案: https://blog.csdn.net/yucaifu1989/article/details/61616870

使用filter過濾xss攻擊,filter實現腳注入攻擊過濾源碼 。  先說一下實現思路:

1. 使用正則表達式的方式實現腳本過濾,這個方法准確率較高,但是可能根據不能的要求會變動;

2. 為了保證配置靈活(包括正則表達式靈活),使用xml配置文件的方式記錄配置信息,配置信息包含是否開啟校驗、是否記錄日志、是否中斷請求、是否替換腳本字符等;

3. 為保證xml與正則表達式的特殊字符不沖突,使用<![CDATA[]]>標簽存放正則表達式,但是在類中需要特殊處理;

4. 通過繼承HttpRequestWrapper的方式實現request中header和parameter信息過濾;

5. xml解析使用dom4j,稍后會對這個工具的使用寫一篇文章,暫時辛苦大家去網站查找資料

6. 使用XSSSecurityManager類實現配置信息加載和處理,XSSSecurityConfig記錄匹配信息,XSSSecurityCon標識程序所需常量;

 

一共改了 7 個文件,如下:

1、XSSHttpRequestWrapper

package com.sg.security;  

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;  

/** 

 * @author winnie 

 * @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;  

    }  

      

}  

 

 

2、XSSSecurityFilter

package com.sg.security;  

  

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;  

  

import org.apache.log4j.Logger;  

  

  

/** 

 * @author winnie 

 * @date  

 * @describe 安全信息審核類 

 */  

public class XSSSecurityFilter implements Filter{  

  

    private static Logger logger = Logger.getLogger(XSSSecurityFilter.class);  

      

    /** 

     * 銷毀操作 

     */  

    public void destroy() {  

        logger.info("XSSSecurityFilter destroy() begin");  

        XSSSecurityManager.destroy();  

        logger.info("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(XSSSecurityCon.FILTER_ERROR_PAGE).forward( httpRequest, httpResponse);  

                return;  

            }  

        }  

        chain.doFilter(xssRequest, response);  

    }  

  

    /** 

     * 初始化操作 

     */  

    public void init(FilterConfig filterConfig) throws ServletException {  

        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");  

        }  

    }  

}  

 

 

3、XSSSecurityManager

package com.sg.security;  

  

import java.util.Iterator;  

import java.util.regex.Pattern;  

  

import javax.servlet.FilterConfig;  

  

import org.apache.log4j.Logger;  

import org.dom4j.DocumentException;  

import org.dom4j.Element;  

import org.dom4j.io.SAXReader;  

  

/** 

 * @author winnie 

 * @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){  

        logger.info("XSSSecurityManager init(FilterConfig config) begin");  

        //初始化過濾配置文件  

        String xssPath = config.getServletContext().getRealPath("/")  

                + config.getInitParameter("securityconfig");  

          

        // 初始化安全過濾配置  

        try {  

            if(initConfig(xssPath)){  

                // 生成匹配器  

                XSS_PATTERN = Pattern.compile(REGEX);  

            }  

        } catch (DocumentException e) {  

            logger.error("安全過濾配置文件xss_security_config.xml加載異常",e);  

        }  

        logger.info("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");  

        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));  

  

        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);  

            }else{  

                logger.error("安全過濾配置文件加載失敗:正則表達式異常 "+tempStr.toString());  

                return false;  

            }  

        }else{  

            logger.error("安全過濾配置文件中沒有 "+XSSSecurityCon.REGEX_LIST+" 屬性");  

            return false;  

        }  

        logger.info("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+" 屬性");  

        }  

        return element.elementText(tagName);  

    }  

      

    /** 

     * 對非法字符進行替換 

     * @param text 

     * @return 

     */  

    public static String securityReplace(String text){  

        if(isNullStr(text)){  

            return text;  

        }else{  

            return text.replaceAll(REGEX, XSSSecurityCon.REPLACEMENT);  

        }  

    }  

      

    /** 

     * 匹配字符是否含特殊字符 

     * @param text 

     * @return 

     */  

    public static boolean matches(String text){  

        if(text==null){  

            return false;  

        }  

        return XSS_PATTERN.matcher(text).matches();  

    }  

      

    /** 

     * 釋放關鍵信息 

     */  

    public static void destroy(){  

        logger.info("XSSSecurityManager.destroy() begin");  

        XSS_PATTERN = null;  

        REGEX = null;  

        logger.info("XSSSecurityManager.destroy() end");  

    }  

      

    /** 

     * 判斷是否為空串,建議放到某個工具類中 

     * @param value 

     * @return 

     */  

    public static boolean isNullStr(String value){  

        return value == null || value.trim().equals("");  

    }  

}  

 

 

 

 

4、 XSSSecurityConfig

package com.sg.security;  

  

/** 

 * @author winnie 

 * 安全過濾配置信息類 

 */  

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;  

      

  

}  

 

 

 

 

5、XSSSecurityCon

package com.sg.security;  

  

/** 

 * @author winnie 

 * @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 = "/common/filtererror.jsp";  

  

}  

 

 

6、xss_security_config.xml

 

<?xml version="1.0" encoding="UTF-8"?>  

<XSSConfig>  

    <!-- 是否進行header校驗 -->  

    <isCheckHeader>false</isCheckHeader>  

    <!-- 是否進行parameter校驗 -->  

    <isCheckParameter>true</isCheckParameter>  

    <!-- 是否記錄日志 -->  

    <isLog>true</isLog>  

    <!-- 是否中斷請求 -->  

    <isChain>false</isChain>  

    <!-- 是否開啟特殊字符替換 -->  

    <replace>true</replace>  

    <!-- 是否開啟特殊url校驗 -->  

    <isCheckUrl>true</isCheckUrl>  

    <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> -->  

        <regex><![CDATA[.*<[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>  

        <!-- 匹配含有字符: 含有回車換行 和 <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>  

 

 

7、web.xml配置

<?xml version="1.0" encoding="UTF-8"?>  

<web-app version="2.5"   

    xmlns="http://java.sun.com/xml/ns/javaee"   

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   

    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   

    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  

  <welcome-file-list>  

    <welcome-file>index.jsp</welcome-file>  

  </welcome-file-list>  

    <!-- 信息安全審核 -->  

    <filter>  

        <filter-name>XSSFiler</filter-name>  

        <filter-class>  

            com.sg.security.XSSSecurityFilter  

        </filter-class>  

        <init-param>  

            <param-name>securityconfig</param-name>  

            <param-value>  

                /WebRoot/config/xss/xss_security_config.xml  

            </param-value>  

        </init-param>  

    </filter>  

    <!-- 攔截請求類型 -->  

    <filter-mapping>  

        <filter-name>XSSFiler</filter-name>  

        <url-pattern>*.jsp</url-pattern>  

    </filter-mapping>  

    <filter-mapping>  

        <filter-name>XSSFiler</filter-name>  

        <url-pattern>*.do</url-pattern>  

    </filter-mapping>  

</web-app>

Xml代碼   收藏代碼
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app version="2.5"   
  3.     xmlns="http://java.sun.com/xml/ns/javaee"   
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
  5.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   
  6.     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
  7.   <welcome-file-list>  
  8.     <welcome-file>index.jsp</welcome-file>  
  9.   </welcome-file-list>  
  10.     <!-- 信息安全審核 -->  
  11.     <filter>  
  12.         <filter-name>XSSFiler</filter-name>  
  13.         <filter-class>  
  14.             com.sg.security.XSSSecurityFilter  
  15.         </filter-class>  
  16.         <init-param>  
  17.             <param-name>securityconfig</param-name>  
  18.             <param-value>  
  19.                 /WebRoot/config/xss/xss_security_config.xml  
  20.             </param-value>  
  21.         </init-param>  
  22.     </filter>  
  23.     <!-- 攔截請求類型 -->  
  24.     <filter-mapping>  
  25.         <filter-name>XSSFiler</filter-name>  
  26.         <url-pattern>*.jsp</url-pattern>  
  27.     </filter-mapping>  
  28.     <filter-mapping>  
  29.         <filter-name>XSSFiler</filter-name>  
  30.         <url-pattern>*.do</url-pattern>  
  31.     </filter-mapping>  
  32. </web-app> 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM