使用filter过滤xss攻击

来源:互联网 发布:淘宝奇葩差评口红 编辑:程序博客网 时间:2024/05/20 14:28
filter实现脚注入攻击过滤源码 

 http://winnie825.iteye.com/blog/1170833

先说一下实现思路:

1. 使用正则表达式的方式实现脚本过滤,这个方法准确率较高,但是可能根据不能的要求会变动;

2. 为了保证配置灵活(包括正则表达式灵活),使用xml配置文件的方式记录配置信息,配置信息包含是否开启校验、是否记录日志、是否中断请求、是否替换脚本字符等;

3. 为保证xml与正则表达式的特殊字符不冲突,使用<![CDATA[]]>标签存放正则表达式,但是在类中需要特殊处理;

4. 通过继承HttpRequestWrapper的方式实现request中header和parameter信息过滤;

5. xml解析使用dom4j,稍后会对这个工具的使用写一篇文章,暂时辛苦大家去网站查找资料(这篇文章很不错http://www.ibm.com/developerworks/cn/xml/x-dom4j.html);

6. 使用XSSSecurityManager类实现配置信息加载和处理,XSSSecurityConfig记录匹配信息,XSSSecurityCon标识程序所需常量;

 


 

功能实现流程

 

 

Java代码  收藏代码
  1. package com.sg.security;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.Enumeration;  
  5. import java.util.Map;  
  6. import java.util.Set;  
  7.   
  8. import javax.servlet.ServletException;  
  9. import javax.servlet.http.HttpServletRequest;  
  10. import javax.servlet.http.HttpServletRequestWrapper;  
  11. import javax.servlet.http.HttpServletResponse;  
  12.   
  13.   
  14. /** 
  15.  * @author winnie 
  16.  * @date  
  17.  * @describe request信息封装类,用于判断、处理request请求中特殊字符 
  18.  */  
  19. public class XSSHttpRequestWrapper extends HttpServletRequestWrapper {  
  20.       
  21.     /** 
  22.      * 封装http请求 
  23.      * @param request 
  24.      */  
  25.     public XSSHttpRequestWrapper(HttpServletRequest request) {  
  26.         super(request);  
  27.     }  
  28.       
  29.     @Override  
  30.     public String getHeader(String name) {  
  31.         String value = super.getHeader(name);  
  32.         // 若开启特殊字符替换,对特殊字符进行替换  
  33.         if(XSSSecurityConfig.REPLACE){  
  34.             XSSSecurityManager.securityReplace(name);  
  35.         }  
  36.         return value;  
  37.     }  
  38.   
  39.     @Override  
  40.     public String getParameter(String name) {  
  41.         String value = super.getParameter(name);  
  42.         // 若开启特殊字符替换,对特殊字符进行替换  
  43.         if(XSSSecurityConfig.REPLACE){  
  44.             XSSSecurityManager.securityReplace(name);  
  45.         }  
  46.         return value;  
  47.     }  
  48.   
  49.     /** 
  50.      * 没有违规的数据,就返回false; 
  51.      *  
  52.      * @return 
  53.      */  
  54.     @SuppressWarnings("unchecked")  
  55.     private boolean checkHeader(){  
  56.         Enumeration<String> headerParams = this.getHeaderNames();  
  57.         while(headerParams.hasMoreElements()){  
  58.             String headerName = headerParams.nextElement();  
  59.             String headerValue = this.getHeader(headerName);  
  60.             if(XSSSecurityManager.matches(headerValue)){  
  61.                 return true;  
  62.             }  
  63.         }  
  64.         return false;  
  65.     }  
  66.       
  67.     /** 
  68.      * 没有违规的数据,就返回false; 
  69.      *  
  70.      * @return 
  71.      */  
  72.     @SuppressWarnings("unchecked")  
  73.     private boolean checkParameter(){  
  74.         Map<String,Object> submitParams = this.getParameterMap();  
  75.         Set<String> submitNames = submitParams.keySet();  
  76.         for(String submitName : submitNames){  
  77.             Object submitValues = submitParams.get(submitName);  
  78.             if(submitValues instanceof String){  
  79.                 if(XSSSecurityManager.matches((String)submitValues)){  
  80.                     return true;  
  81.                 }  
  82.             }else if(submitValues instanceof String[]){  
  83.                 for(String submitValue : (String[])submitValues){  
  84.                     if(XSSSecurityManager.matches((String)submitValue)){  
  85.                         return true;  
  86.                     }  
  87.                 }  
  88.             }  
  89.         }  
  90.         return false;  
  91.     }  
  92.       
  93.      
  94.     /** 
  95.      * 没有违规的数据,就返回false; 
  96.      * 若存在违规数据,根据配置信息判断是否跳转到错误页面 
  97.      * @param response 
  98.      * @return 
  99.      * @throws IOException  
  100.      * @throws ServletException  
  101.      */  
  102.     public boolean validateParameter(HttpServletResponse response) throws ServletException, IOException{  
  103.         // 开始header校验,对header信息进行校验  
  104.         if(XSSSecurityConfig.IS_CHECK_HEADER){  
  105.             if(this.checkHeader()){  
  106.                 return true;  
  107.             }  
  108.         }  
  109.         // 开始parameter校验,对parameter信息进行校验  
  110.         if(XSSSecurityConfig.IS_CHECK_PARAMETER){  
  111.             if(this.checkParameter()){  
  112.                 return true;  
  113.             }  
  114.         }  
  115.         return false;  
  116.     }  
  117.       
  118. }  

 

 

Java代码  收藏代码
  1. /** 
  2.  *  
  3.  */  
  4. package com.sg.security;  
  5.   
  6. import java.io.IOException;  
  7.   
  8. import javax.servlet.Filter;  
  9. import javax.servlet.FilterChain;  
  10. import javax.servlet.FilterConfig;  
  11. import javax.servlet.ServletException;  
  12. import javax.servlet.ServletRequest;  
  13. import javax.servlet.ServletResponse;  
  14. import javax.servlet.http.HttpServletRequest;  
  15. import javax.servlet.http.HttpServletResponse;  
  16.   
  17. import org.apache.log4j.Logger;  
  18.   
  19.   
  20. /** 
  21.  * @author winnie 
  22.  * @date  
  23.  * @describe 安全信息审核类 
  24.  */  
  25. public class XSSSecurityFilter implements Filter{  
  26.   
  27.     private static Logger logger = Logger.getLogger(XSSSecurityFilter.class);  
  28.       
  29.     /** 
  30.      * 销毁操作 
  31.      */  
  32.     public void destroy() {  
  33.         logger.info("XSSSecurityFilter destroy() begin");  
  34.         XSSSecurityManager.destroy();  
  35.         logger.info("XSSSecurityFilter destroy() end");  
  36.     }  
  37.   
  38.     /** 
  39.      * 安全审核 
  40.      * 读取配置信息 
  41.      */  
  42.     public void doFilter(ServletRequest request, ServletResponse response,  
  43.             FilterChain chain) throws IOException, ServletException {  
  44.         // 判断是否使用HTTP  
  45.         checkRequestResponse(request, response);  
  46.         // 转型  
  47.         HttpServletRequest httpRequest = (HttpServletRequest) request;  
  48.         HttpServletResponse httpResponse = (HttpServletResponse) response;  
  49.         // http信息封装类  
  50.         XSSHttpRequestWrapper xssRequest = new XSSHttpRequestWrapper(httpRequest);  
  51.           
  52.         // 对request信息进行封装并进行校验工作,若校验失败(含非法字符),根据配置信息进行日志记录和请求中断处理  
  53.         if(xssRequest.validateParameter(httpResponse)){  
  54.             if(XSSSecurityConfig.IS_LOG){  
  55.                 // 记录攻击访问日志  
  56.                 // 可使用数据库、日志、文件等方式  
  57.             }  
  58.             if(XSSSecurityConfig.IS_CHAIN){  
  59.                 httpRequest.getRequestDispatcher(XSSSecurityCon.FILTER_ERROR_PAGE).forward( httpRequest, httpResponse);  
  60.                 return;  
  61.             }  
  62.         }  
  63.         chain.doFilter(xssRequest, response);  
  64.     }  
  65.   
  66.     /** 
  67.      * 初始化操作 
  68.      */  
  69.     public void init(FilterConfig filterConfig) throws ServletException {  
  70.         XSSSecurityManager.init(filterConfig);  
  71.     }  
  72.   
  73.     /** 
  74.      * 判断Request ,Response 类型 
  75.      * @param request 
  76.      *            ServletRequest 
  77.      * @param response 
  78.      *            ServletResponse 
  79.      * @throws ServletException  
  80.      */  
  81.     private void checkRequestResponse(ServletRequest request,  
  82.             ServletResponse response) throws ServletException {  
  83.         if (!(request instanceof HttpServletRequest)) {  
  84.             throw new ServletException("Can only process HttpServletRequest");  
  85.   
  86.         }  
  87.         if (!(response instanceof HttpServletResponse)) {  
  88.             throw new ServletException("Can only process HttpServletResponse");  
  89.         }  
  90.     }  
  91. }  

 

Java代码  收藏代码
  1. /** 
  2.  *  
  3.  */  
  4. package com.sg.security;  
  5.   
  6. import java.util.Iterator;  
  7. import java.util.regex.Pattern;  
  8.   
  9. import javax.servlet.FilterConfig;  
  10.   
  11. import org.apache.log4j.Logger;  
  12. import org.dom4j.DocumentException;  
  13. import org.dom4j.Element;  
  14. import org.dom4j.io.SAXReader;  
  15.   
  16. /** 
  17.  * @author winnie 
  18.  * @date  
  19.  * @describe 安全过滤配置管理类,由XSSSecurityManger修改 
  20.  */  
  21. public class XSSSecurityManager {  
  22.       
  23.     private static Logger logger = Logger.getLogger(XSSSecurityManager.class);  
  24.       
  25.     /** 
  26.      * REGEX:校验正则表达式 
  27.      */  
  28.     public static String REGEX;  
  29.       
  30.      /** 
  31.      * 特殊字符匹配 
  32.      */  
  33.     private static Pattern XSS_PATTERN ;  
  34.       
  35.       
  36.     private XSSSecurityManager(){  
  37.         //不可被实例化  
  38.     }  
  39.       
  40.     public static void init(FilterConfig config){  
  41.         logger.info("XSSSecurityManager init(FilterConfig config) begin");  
  42.         //初始化过滤配置文件  
  43.         String xssPath = config.getServletContext().getRealPath("/")  
  44.                 + config.getInitParameter("securityconfig");  
  45.           
  46.         // 初始化安全过滤配置  
  47.         try {  
  48.             if(initConfig(xssPath)){  
  49.                 // 生成匹配器  
  50.                 XSS_PATTERN = Pattern.compile(REGEX);  
  51.             }  
  52.         } catch (DocumentException e) {  
  53.             logger.error("安全过滤配置文件xss_security_config.xml加载异常",e);  
  54.         }  
  55.         logger.info("XSSSecurityManager init(FilterConfig config) end");  
  56.     }  
  57.       
  58.     /** 
  59.      * 读取安全审核配置文件xss_security_config.xml 
  60.      * 设置XSSSecurityConfig配置信息 
  61.      * @param path 配置文件地址 eg C:/apache-tomcat-6.0.33/webapps/security_filter/WebRoot/config/xss/xss_security_config.xml 
  62.      * @return  
  63.      * @throws DocumentException 
  64.      */  
  65.     @SuppressWarnings("unchecked")  
  66.     public static boolean initConfig(String path) throws DocumentException {  
  67.         logger.info("XSSSecurityManager.initConfig(String path) begin");  
  68.         Element superElement = new SAXReader().read(path).getRootElement();  
  69.         XSSSecurityConfig.IS_CHECK_HEADER = new Boolean(getEleValue(superElement,XSSSecurityCon.IS_CHECK_HEADER));  
  70.         XSSSecurityConfig.IS_CHECK_PARAMETER = new Boolean(getEleValue(superElement,XSSSecurityCon.IS_CHECK_PARAMETER));  
  71.         XSSSecurityConfig.IS_LOG = new Boolean(getEleValue(superElement,XSSSecurityCon.IS_LOG));  
  72.         XSSSecurityConfig.IS_CHAIN = new Boolean(getEleValue(superElement,XSSSecurityCon.IS_CHAIN));  
  73.         XSSSecurityConfig.REPLACE = new Boolean(getEleValue(superElement,XSSSecurityCon.REPLACE));  
  74.   
  75.         Element regexEle = superElement.element(XSSSecurityCon.REGEX_LIST);  
  76.           
  77.         if(regexEle != null){  
  78.             Iterator<Element> regexIt = regexEle.elementIterator();  
  79.             StringBuffer tempStr = new StringBuffer("^");  
  80.             //xml的cdata标签传输数据时,会默认在\前加\,需要将\\替换为\  
  81.             while(regexIt.hasNext()){  
  82.                 Element regex = (Element)regexIt.next();  
  83.                 String tmp = regex.getText();  
  84.                 tmp = tmp.replaceAll("\\\\\\\\", "\\\\");  
  85.                 tempStr.append(tmp);  
  86.                 tempStr.append("|");  
  87.             }  
  88.             if(tempStr.charAt(tempStr.length()-1)=='|'){  
  89.                 REGEX= tempStr.substring(0, tempStr.length()-1)+"$";  
  90.                 logger.info("安全匹配规则"+REGEX);  
  91.             }else{  
  92.                 logger.error("安全过滤配置文件加载失败:正则表达式异常 "+tempStr.toString());  
  93.                 return false;  
  94.             }  
  95.         }else{  
  96.             logger.error("安全过滤配置文件中没有 "+XSSSecurityCon.REGEX_LIST+" 属性");  
  97.             return false;  
  98.         }  
  99.         logger.info("XSSSecurityManager.initConfig(String path) end");  
  100.         return true;  
  101.   
  102.     }  
  103.       
  104.     /** 
  105.      * 从目标element中获取指定标签信息,若找不到该标签,记录错误日志 
  106.      * @param element 目标节点 
  107.      * @param tagName 制定标签 
  108.      * @return  
  109.      */  
  110.     private static String getEleValue(Element element, String tagName){  
  111.         if (isNullStr(element.elementText(tagName))){  
  112.             logger.error("安全过滤配置文件中没有 "+XSSSecurityCon.REGEX_LIST+" 属性");  
  113.         }  
  114.         return element.elementText(tagName);  
  115.     }  
  116.       
  117.     /** 
  118.      * 对非法字符进行替换 
  119.      * @param text 
  120.      * @return 
  121.      */  
  122.     public static String securityReplace(String text){  
  123.         if(isNullStr(text)){  
  124.             return text;  
  125.         }else{  
  126.             return text.replaceAll(REGEX, XSSSecurityCon.REPLACEMENT);  
  127.         }  
  128.     }  
  129.       
  130.     /** 
  131.      * 匹配字符是否含特殊字符 
  132.      * @param text 
  133.      * @return 
  134.      */  
  135.     public static boolean matches(String text){  
  136.         if(text==null){  
  137.             return false;  
  138.         }  
  139.         return XSS_PATTERN.matcher(text).matches();  
  140.     }  
  141.       
  142.     /** 
  143.      * 释放关键信息 
  144.      */  
  145.     public static void destroy(){  
  146.         logger.info("XSSSecurityManager.destroy() begin");  
  147.         XSS_PATTERN = null;  
  148.         REGEX = null;  
  149.         logger.info("XSSSecurityManager.destroy() end");  
  150.     }  
  151.       
  152.     /** 
  153.      * 判断是否为空串,建议放到某个工具类中 
  154.      * @param value 
  155.      * @return 
  156.      */  
  157.     public static boolean isNullStr(String value){  
  158.         return value == null || value.trim().equals("");  
  159.     }  
  160. }  

 

 

Java代码  收藏代码
  1. /** 
  2.  *  
  3.  */  
  4. package com.sg.security;  
  5.   
  6. /** 
  7.  * @author winnie 
  8.  * 安全过滤配置信息类 
  9.  */  
  10. public class XSSSecurityConfig {  
  11.       
  12.     /** 
  13.      * CHECK_HEADER:是否开启header校验 
  14.      */  
  15.     public static boolean IS_CHECK_HEADER;   
  16.       
  17.     /** 
  18.      * CHECK_PARAMETER:是否开启parameter校验 
  19.      */  
  20.     public static boolean IS_CHECK_PARAMETER;  
  21.       
  22.     /** 
  23.      * IS_LOG:是否记录日志 
  24.      */  
  25.     public static boolean IS_LOG;  
  26.       
  27.     /** 
  28.      * IS_LOG:是否中断操作 
  29.      */  
  30.     public static boolean IS_CHAIN;  
  31.       
  32.     /** 
  33.      * REPLACE:是否开启替换 
  34.      */  
  35.     public static boolean REPLACE;  
  36.       
  37.   
  38. }  

 

 

Java代码  收藏代码
  1. /** 
  2.  *  
  3.  */  
  4. package com.sg.security;  
  5.   
  6. /** 
  7.  * @author winnie 
  8.  * @date  
  9.  * @describe 
  10.  */  
  11. public class XSSSecurityCon {  
  12.   
  13.     /** 
  14.      * 配置文件标签 isCheckHeader 
  15.      */  
  16.     public static String IS_CHECK_HEADER = "isCheckHeader";  
  17.   
  18.     /** 
  19.      * 配置文件标签 isCheckParameter 
  20.      */  
  21.     public static String IS_CHECK_PARAMETER = "isCheckParameter";  
  22.   
  23.     /** 
  24.      * 配置文件标签 isLog 
  25.      */  
  26.     public static String IS_LOG = "isLog";  
  27.   
  28.     /** 
  29.      * 配置文件标签 isChain 
  30.      */  
  31.     public static String IS_CHAIN = "isChain";  
  32.   
  33.     /** 
  34.      * 配置文件标签 replace 
  35.      */  
  36.     public static String REPLACE = "replace";  
  37.   
  38.     /** 
  39.      * 配置文件标签 regexList 
  40.      */  
  41.     public static String REGEX_LIST = "regexList";  
  42.   
  43.     /** 
  44.      * 替换非法字符的字符串 
  45.      */  
  46.     public static String REPLACEMENT = "";  
  47.   
  48.     /** 
  49.      * FILTER_ERROR_PAGE:过滤后错误页面 
  50.      */  
  51.     public static String FILTER_ERROR_PAGE = "/common/filtererror.jsp";  
  52.   
  53. }  

 

xss_security_config.xml

Xml代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <XSSConfig>  
  3.     <!-- 是否进行header校验 -->  
  4.     <isCheckHeader>false</isCheckHeader>  
  5.     <!-- 是否进行parameter校验 -->  
  6.     <isCheckParameter>true</isCheckParameter>  
  7.     <!-- 是否记录日志 -->  
  8.     <isLog>true</isLog>  
  9.     <!-- 是否中断请求 -->  
  10.     <isChain>false</isChain>  
  11.     <!-- 是否开启特殊字符替换 -->  
  12.     <replace>true</replace>  
  13.     <!-- 是否开启特殊url校验 -->  
  14.     <isCheckUrl>true</isCheckUrl>  
  15.     <regexList>  
  16.         <!-- 匹配含有字符: alert( ) -->  
  17.         <regex><![CDATA[.*[A|a][L|l][E|e][R|r][T|t]\\s*\\(.*\\).*]]></regex>  
  18.         <!-- 匹配含有字符: window.location = -->  
  19.         <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>  
  20.         <!-- 匹配含有字符:style = x:ex pression ( ) -->  
  21.         <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>  
  22.         <!-- 匹配含有字符: document.cookie -->  
  23.         <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>  
  24.         <!-- 匹配含有字符: eval( ) -->  
  25.         <regex><![CDATA[.*[E|e][V|v][A|a][L|l]\\s*\\(.*\\).*]]></regex>  
  26.         <!-- 匹配含有字符: unescape() -->  
  27.         <regex><![CDATA[.*[U|u][N|n][E|e][S|s][C|c][A|a][P|p][E|e]\\s*\\(.*\\).*]]></regex>  
  28.         <!-- 匹配含有字符: execscript( ) -->  
  29.         <regex><![CDATA[.*[E|e][X|x][E|e][C|c][S|s][C|c][R|r][I|i][P|p][T|t]\\s*\\(.*\\).*]]></regex>  
  30.         <!-- 匹配含有字符: msgbox( ) -->  
  31.         <regex><![CDATA[.*[M|m][S|s][G|g][B|b][O|o][X|x]\\s*\\(.*\\).*]]></regex>  
  32.         <!-- 匹配含有字符: confirm( ) -->  
  33.         <regex><![CDATA[.*[C|c][O|o][N|n][F|f][I|i][R|r][M|m]\\s*\\(.*\\).*]]></regex>  
  34.         <!-- 匹配含有字符: prompt( ) -->  
  35.         <regex><![CDATA[.*[P|p][R|r][O|o][M|m][P|p][T|t]\\s*\\(.*\\).*]]></regex>  
  36.         <!-- 匹配含有字符: <script> </script> -->  
  37.         <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>  
  38.         <!-- 匹配含有字符: 含有一个符号: "  -->  
  39.         <regex><![CDATA[[.&[^\"]]*\"[.&[^\"]]*]]></regex>  
  40.         <!-- 匹配含有字符: 含有一个符号: '  -->  
  41.         <regex><![CDATA[[.&[^']]*'[.&[^']]*]]></regex>  
  42.         <!-- 匹配含有字符: 含有回车换行 和 <script> </script> -->  
  43.         <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>  
  44.     </regexList>  
  45. </XSSConfig>  

 

web.xml配置

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>  

 

0 0