zoukankan      html  css  js  c++  java
  • 【漏洞三】跨站点脚本(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| | | |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| | | |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> 
  • 相关阅读:
    Spinner用法与ListView用法
    ViewPager实现选项卡功能
    android:layout_weight的真实含义
    vb和vb.net事件机制
    go
    挨踢江湖之十一
    蓝桥杯-地铁换乘
    【Android LibGDX游戏引擎开发教程】第06期:图形图像的绘制(下)图片整合工具的使用
    Eclipse3.6 添加JUnit源代码
    【分享】如何使用sublime代码片段快速输入PHP头部版本声明
  • 原文地址:https://www.cnblogs.com/651434092qq/p/11507092.html
Copyright © 2011-2022 走看看