cookie跨站脚本漏洞解决方案

近日项目碰到一个跨脚本注入的问题:

这安全测评工具也是厉害了,直接将脚本注入到cookie里头,以前没有碰到这样的情况。

之前写过一篇文章过滤跨脚本注入的问题。《浅谈XSS攻击原理与解决方法》关于跨脚本注入的问题,不晓得原理的同学可以看下。但是里头没有处理cookie注入的问题。接下来介绍下如何处理。

关键代码在这里:首先获取到cookie,检查下是否有敏感字符,如果有的话,就进行替换。

//防止cookie跨站注入问题,替换敏感字符。
         Cookie[] cookies = ((HttpServletRequest) request).getCookies();
         if(cookies!=null) {
            for(Cookie cookie: cookies){     
                if(CookieFilterUtil.isValidate(cookie.getValue())){
                    cookie.setValue(CookieFilterUtil.xssClean(cookie.getValue()));
                    Cookie newCookie=cookie;
                    cookie.setMaxAge(0);
                    ((HttpServletResponse) response).addCookie(newCookie);
                    break;
                }                 
             }
         }

CookieFilter.java

public class CookieFilterUtil {
     //将敏感字符进行替换
     public static String xssClean(String value) {
            //ClassLoaderUtils.getResourceAsStream("classpath:antisamy-slashdot.xml", XssHttpServletRequestWrapper.class)
            if (value != null) {
                // NOTE: It's highly recommended to use the ESAPI library and
                // uncomment the following line to
                // avoid encoded attacks.
                // value = encoder.canonicalize(value);
                value = value.replaceAll("\0", "");
                
                // Avoid anything between script tags
                Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>",
                        Pattern.CASE_INSENSITIVE);
                value = scriptPattern.matcher(value).replaceAll("");

                // Avoid anything in a src='...' type of expression
                scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'",
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                | Pattern.DOTALL);
                value = scriptPattern.matcher(value).replaceAll("");
                // Avoid anything in a href='...' type of expression
                scriptPattern = Pattern.compile("href[\r\n]*=[\r\n]*\\\"(.*?)\\\"",
                                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                            | Pattern.DOTALL);
                value = scriptPattern.matcher(value).replaceAll("");
                

                // Remove any lonesome </script> tag
                scriptPattern = Pattern.compile("</script>",
                        Pattern.CASE_INSENSITIVE);
                value = scriptPattern.matcher(value).replaceAll("");

                // Remove any lonesome <script ...> tag
                scriptPattern = Pattern.compile("<script(.*?)>",
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                | Pattern.DOTALL);
                value = scriptPattern.matcher(value).replaceAll("");

                // Avoid eval(...) expressions
                scriptPattern = Pattern.compile("eval\\((.*?)\\)",
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                | Pattern.DOTALL);
                value = scriptPattern.matcher(value).replaceAll("");

                // Avoid expression(...) expressions
                scriptPattern = Pattern.compile("expression\\((.*?)\\)",
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                | Pattern.DOTALL);
                value = scriptPattern.matcher(value).replaceAll("");

                // Avoid javascript:... expressions
                scriptPattern = Pattern.compile("javascript:",
                        Pattern.CASE_INSENSITIVE);
                value = scriptPattern.matcher(value).replaceAll("");

                // Avoid vbscript:... expressions
                scriptPattern = Pattern.compile("vbscript:",
                        Pattern.CASE_INSENSITIVE);
                value = scriptPattern.matcher(value).replaceAll("");

                // Avoid onload= expressions
                scriptPattern = Pattern.compile("onload(.*?)=",
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                | Pattern.DOTALL);
                value = scriptPattern.matcher(value).replaceAll("");
            }  
              return value; 
    }
    //校验是否含有敏感字符
    public static boolean isValidate(String value) {
            //ClassLoaderUtils.getResourceAsStream("classpath:antisamy-slashdot.xml", XssHttpServletRequestWrapper.class)
            boolean flag=false;
            if (value != null) {
                // NOTE: It's highly recommended to use the ESAPI library and
                // uncomment the following line to
                // avoid encoded attacks.
                // value = encoder.canonicalize(value);
                value = value.replaceAll("\0", "");
                
                // Avoid anything between script tags
                Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>",
                        Pattern.CASE_INSENSITIVE);
                if(scriptPattern.matcher(value).find()){
                    flag=true;
                    return flag;
                }
    
                // Avoid anything in a src='...' type of expression
                scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'",
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                | Pattern.DOTALL);
                if(scriptPattern.matcher(value).find()){
                    flag=true;
                    return flag;
                }
                
                // Avoid anything in a href='...' type of expression
                scriptPattern = Pattern.compile("href[\r\n]*=[\r\n]*\\\"(.*?)\\\"",
                                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                            | Pattern.DOTALL);
                if(scriptPattern.matcher(value).find()){
                    flag=true;
                    return flag;
                }
                
    
                // Remove any lonesome </script> tag
                scriptPattern = Pattern.compile("</script>",
                        Pattern.CASE_INSENSITIVE);
                if(scriptPattern.matcher(value).find()){
                    flag=true;
                    return flag;
                }
    
                // Remove any lonesome <script ...> tag
                scriptPattern = Pattern.compile("<script(.*?)>",
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                | Pattern.DOTALL);
                if(scriptPattern.matcher(value).find()){
                    flag=true;
                    return flag;
                }
    
                // Avoid eval(...) expressions
                scriptPattern = Pattern.compile("eval\\((.*?)\\)",
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                | Pattern.DOTALL);
                if(scriptPattern.matcher(value).find()){
                    flag=true;
                    return flag;
                }
                
                // Avoid expression(...) expressions
                scriptPattern = Pattern.compile("expression\\((.*?)\\)",
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                | Pattern.DOTALL);
                if(scriptPattern.matcher(value).find()){
                    flag=true;
                    return flag;
                }
                
                // Avoid javascript:... expressions
                scriptPattern = Pattern.compile("javascript:",
                        Pattern.CASE_INSENSITIVE);
                if(scriptPattern.matcher(value).find()){
                    flag=true;
                    return flag;
                }
    
                // Avoid vbscript:... expressions
                scriptPattern = Pattern.compile("vbscript:",
                        Pattern.CASE_INSENSITIVE);
                if(scriptPattern.matcher(value).find()){
                    flag=true;
                    return flag;
                }
                
                // Avoid onload= expressions
                scriptPattern = Pattern.compile("onload(.*?)=",
                        Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                | Pattern.DOTALL);
                if(scriptPattern.matcher(value).find()){
                    flag=true;
                    return flag;
                }
            }  
            return flag; 
          }
}
XssFilter.java
public class XssFilter implements Filter {
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        
         //防止cookie跨站注入问题,替换敏感字符。
         boolean flag=false;
         Cookie[] cookies = ((HttpServletRequest) request).getCookies();
         if(cookies!=null) {
            for(Cookie cookie: cookies){     
                if(CookieFilterUtil.isValidate(cookie.getValue())){
                    flag=true;
                    cookie.setValue(CookieFilterUtil.xssClean(cookie.getValue()));
                    Cookie newCookie=cookie;
                    cookie.setMaxAge(0);
                    ((HttpServletResponse) response).addCookie(newCookie);
                    break;
                }                 
             }
         }
         
         //如果存在跨站注入问题,跳转到登录页。
         if(!flag){
             String path = ((HttpServletRequest) request).getContextPath();
             String protAndPath = request.getServerPort() == 80 ? "" : ":"
                     + request.getServerPort();
             String basePath = request.getScheme() + "://"
                     + request.getServerName() + protAndPath + path + "/";
             String returnUrl = basePath+"login.do";
             request.setCharacterEncoding("UTF-8");
             response.setContentType("text/html; charset=UTF-8"); // 转码
             response.getWriter().println(
                           "<script language=\"javascript\">if(window.opener==null){window.top.location.href=\""
                                   + returnUrl
                                   + "\";}else{window.opener.top.location.href=\""
                                   + returnUrl
                                   + "\";window.close();}</script>");
         }else{
             chain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) request), response);
         }
         
    }

    @Override
    public void destroy() {
    }
    
   
}

 这儿的操作如果有敏感字符,那么就调整到登录首页,删除cookie,当然也可以不处理,像以下代码这样

 //防止cookie跨站注入问题,替换敏感字符。
         Cookie[] cookies = ((HttpServletRequest) request).getCookies();
         if(cookies!=null) {
            for(Cookie cookie: cookies){     
                if(CookieFilterUtil.isValidate(cookie.getValue())){
                    cookie.setValue(CookieFilterUtil.xssClean(cookie.getValue()));
                    Cookie newCookie=cookie;
                    cookie.setMaxAge(0);
                    ((HttpServletResponse) response).addCookie(newCookie);
                    break;
                }                 
             }
         }         
         chain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) request), response);

xss过滤器实现XssHttpServletRequestWrapper.java

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    @SuppressWarnings("rawtypes")
    public Map<String,String[]> getParameterMap(){
        Map<String,String[]> request_map = super.getParameterMap();
        Iterator iterator = request_map.entrySet().iterator();
        while(iterator.hasNext()){
            Map.Entry me = (Map.Entry)iterator.next();
            String[] values = (String[])me.getValue();
            for(int i = 0 ; i < values.length ; i++){
                values[i]=HtmlRegexpUtil.fiterHtmlByTagArr(values[i]);
                values[i] = xssClean(values[i]);
            }
        }
        
        return request_map;
    }
     public String[] getParameterValues(String paramString)
      {
        String[] arrayOfString1 = super.getParameterValues(paramString);
        if (arrayOfString1 == null)
          return null;
        int i = arrayOfString1.length;
        String[] arrayOfString2 = new String[i];
        for (int j = 0; j < i; j++){
            arrayOfString1[j]=HtmlRegexpUtil.fiterHtmlByTagArr(arrayOfString1[j]);
            arrayOfString2[j] = xssClean(arrayOfString1[j]);
        }
        return arrayOfString2;
      }

      public String getParameter(String paramString)
      {
        String str = super.getParameter(paramString);
        if (str == null)
          return null;
        return xssClean(str);
      }

      public String getHeader(String paramString)
      {
        String str = super.getHeader(paramString);
        if (str == null)
          return null;
        str = str.replaceAll("\r|\n", "");
        return xssClean(str);
      }
      
      
      private String xssClean(String value) {
        //ClassLoaderUtils.getResourceAsStream("classpath:antisamy-slashdot.xml", XssHttpServletRequestWrapper.class)
        if (value != null) {
            // NOTE: It's highly recommended to use the ESAPI library and
            // uncomment the following line to
            // avoid encoded attacks.
            // value = encoder.canonicalize(value);
            value = value.replaceAll("\0", "");
            
            // Avoid anything between script tags
            Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>",
                    Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid anything in a src='...' type of expression
            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                            | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
            // Avoid anything in a href='...' type of expression
            scriptPattern = Pattern.compile("href[\r\n]*=[\r\n]*\\\"(.*?)\\\"",
                                Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                                        | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
            

            // Remove any lonesome </script> tag
            scriptPattern = Pattern.compile("</script>",
                    Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");

            // Remove any lonesome <script ...> tag
            scriptPattern = Pattern.compile("<script(.*?)>",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                            | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid eval(...) expressions
            scriptPattern = Pattern.compile("eval\\((.*?)\\)",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                            | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid expression(...) expressions
            scriptPattern = Pattern.compile("expression\\((.*?)\\)",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                            | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid javascript:... expressions
            scriptPattern = Pattern.compile("javascript:",
                    Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid vbscript:... expressions
            scriptPattern = Pattern.compile("vbscript:",
                    Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid onload= expressions
            scriptPattern = Pattern.compile("onload(.*?)=",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE
                            | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
        }  
          return value; 
          }
}

 

posted @ 2018-10-17 10:00  shawWey  阅读(2803)  评论(0编辑  收藏  举报