欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

防sql注入和跨脚本攻击

程序员文章站 2022-03-11 21:34:41
...
公司做的一个web项目中有这个功能,记录并学习下。在web系统中很多页面有文本输入的功能,有些不严谨的程序,通过写一些特殊字符,js片段,sql脚步会导致程序出现bug,现在通过一个统一的功能进行屏蔽。主要通过过滤器、xml解析的机制实现。
1、首先在web.xml里面增加过滤器配置。
 <!-- 防sql注入和跨脚本攻击 -->
   <filter>
    <filter-name>webSecurityFilter</filter-name>
    <filter-class>com.zhgl.filter.WebSecurityFilter</filter-class>
	<init-param>
      <param-name>filter_xss</param-name>
      <param-value>true</param-value>
    </init-param>
	<init-param>
      <param-name>filter_sql_injection</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>

2、过滤器功能代码
/**
 * project : yyzhglpt_public
 * package :com.zhgl.filter
 * file : WebSecurityFilter.java
 */
package com.zhgl.filter;

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

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 com.yyzhglpt.util.StringUtil;
import com.zhgl.util.MessageStreamResult;

/**
 * Specification : 文档说明
 */
public class WebSecurityFilter implements Filter
{
    public static final String FILTER_XSS_PARAM_NAME = "filter_xss";
    
    public static final String FILTER_SQL_INJECTION_PARAM_NAME = "filter_sql_injection";
    
    boolean filterXSS = true;
    
    boolean filterSQL = true;
    
    @Override
    public void destroy()
    {
    }
    
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
        throws IOException, ServletException
    {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        WebXssEscapeFilterUtil filterUtil = WebXssEscapeFilterUtil.getInstance();
        String cutUrl = ((HttpServletRequest)request).getRequestURI();
        String cutedUrl = cutUrl.substring(cutUrl.lastIndexOf("/") + 1);
        String actionName = request.getParameter("action");
        if (StringUtil.isNotEmpty(cutedUrl) && StringUtil.isNotEmpty(actionName))
        {
            WebXssEscapeFilterRule urlRule = filterUtil.getFilterRule(cutedUrl, actionName);
            if (urlRule != null)
            {
                Map<String, String[]> paramMap = request.getParameterMap();
                Set<String> entries = paramMap.keySet();
                for (String entry : entries)
                {
                    String paramName = entry;
                    String[] valueObj = paramMap.get(paramName);
                    if (urlRule.getParams().contains(paramName))
                    {
                        for(String str: valueObj){
                            if(!urlRule.getDefender().doFilter(str)){
                                if("html".equals(urlRule.getResultType())){
                                    try
                                    {
                                        MessageStreamResult.msgStreamResult(response, "您输入的参数有非法字符,请输入正确的参数!");
                                        return;
                                    }
                                    catch (Exception e)
                                    {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                    }
                                }else if("json".equals(urlRule.getResultType())){
                                    try
                                    {
                                        MessageStreamResult.msgStreamResult(response, "{\"msg\":\"您输入的参数有非法字符,请输入正确的参数!\",\"success\":false}");
                                        return;
                                    }
                                    catch (Exception e)
                                    {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                    }
                                }
                               // {\"msg\":\"\",\"success\":true}
                            }
                        }
                    }
                    
                }
            }
        }
        
        //WebSecurityWrapper wrapper = new WebSecurityWrapper(servletRequest, WebXssEscapeFilterUtil.getInstance());
        filterChain.doFilter(servletRequest, servletResponse);
    }
    
    @Override
    public void init(FilterConfig config)
        throws ServletException
    {
        String filterXSSParam = config.getInitParameter(FILTER_XSS_PARAM_NAME);
        String filterSQLParam = config.getInitParameter(FILTER_SQL_INJECTION_PARAM_NAME);
        filterXSS = new Boolean(filterXSSParam);
        filterSQL = new Boolean(filterSQLParam);
    }
    
}



3、哪些action需要进行过滤,具体的哪些字段需要过滤,通过xss-servlet-filter-rule.xml文件配置规则。

<?xml version="1.0" encoding="UTF-8"?>
<config>
	<!-- 默认过滤规则 -->
	<default>
		<defender>
			<name>xssDefaultDefender</name>
			<class>com.zhgl.filter.defender.DefaultDefender</class>
		</defender>
	</default>
	<!-- url规则设置 -->
	<url-rule-set>
		<url-rule><!-- 一个xxx.do一个url-rule   -->
			<url>jxfa.do</url><!-- 拦截的URL -->
			<actions>
				<action name="saveFa" resultType="html"><!-- 具体的action名称可多个    请求链接的返回类型 html 为 普通的字符流  json为返回普通接送字符流-->
					<params>
						<param name="famc"/><!-- 需要拦截验证是否有特殊字段的字段  目前特殊字符为  < > '  "  /  &  \  -->
						<param name="fams"/><!-- 需要拦截验证是否有特殊字段的字段   目前特殊字符为  < > '  "  /  &  \  -->
					</params>
				</action>
				<action name="test" resultType="json">
					<params>
						<param name="query1" />
						<param name="query2" />
						<param name="query3" />
					</params>
				</action>
			</actions>
		</url-rule>
</url-rule-set>
</config>

4、解析xss-servlet-filter-rule.xml文件相关的类。
1)、WebSecurityWrapper类
/**
 * Copyright 2014 winning, Inc. All rights reserved.
 * project : yyzhglpt_public
 * package :com.zhgl.filter
 * file : WebSecurityWrapper.java
 * date :2015-11-23
 */
package com.zhgl.filter;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
 * Specification : 文档说明
 */
public class WebSecurityWrapper  extends HttpServletRequestWrapper {
	private static final String EVENTS = "((?i)onload|onunload|onchange|onsubmit|onreset" + "|onselect|onblur|onfocus|onkeydown|onkeypress|onkeyup"
	    + "|onclick|ondblclick|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup)";
	//private static final String XSS_HTML_TAG = "(%3C)|(%3E)|[<>]+|[']+|[\"]+|(%27)|(%22)|(%2527)";
	//private static final String XSS_INJECTION = "((%22%20)|(%22\\s)|('%22)|(%22\\+))\\w.*|(\\s|%20)" + EVENTS + ".*|(%3D)";
	//private static final String XSS_REGEX = XSS_HTML_TAG + "|" + XSS_INJECTION;
	private static final String XSS_REGEX = "(%3C)|(%3E)|[<>]+";
	private static final String SQL_REGEX = "";
	
	boolean filterXSS = true;
	boolean filterSQL = true;
	
	public WebSecurityWrapper(HttpServletRequest request, boolean filterXSS, boolean filterSQL) {
		super(request);
		this.filterXSS = filterXSS;
		this.filterSQL = filterSQL;
	}
	
	public WebSecurityWrapper(HttpServletRequest request) {
		this(request,true,true);
	}
	
	
	@Override
	public String getParameter(String name) {
	  String value = super.getParameter(name);
	  return filterParamString(value);
	}
	
	@Override
	public Map<String, String[]> getParameterMap() {
	  Map<String, String[]> rawMap = super.getParameterMap();
	  Map<String, String[]> filteredMap = new HashMap<String, String[]>(rawMap.size());
	  Set<String> keys = rawMap.keySet();
	  for (String key : keys) {
	    String[] rawValue = rawMap.get(key);
	    String[] filteredValue = filterStringArray(rawValue);
	    filteredMap.put(key, filteredValue);
	  }
	  return filteredMap;
	}
	
	protected String[] filterStringArray(String[] rawValue) {
	  String[] filteredArray = new String[rawValue.length];
	  for (int i = 0; i < rawValue.length; i++) {
	    filteredArray[i] = filterParamString(rawValue[i]);
	  }
	  return filteredArray;
	}
	
	@Override
	public String[] getParameterValues(String name) {
	  String[] rawValues = super.getParameterValues(name);
	  if (rawValues == null)
	    return null;
	  String[] filteredValues = new String[rawValues.length];
	  for (int i = 0; i < rawValues.length; i++) {
	    filteredValues[i] = filterParamString(rawValues[i]);
	  }
	  return filteredValues;
	}
	
	protected String filterParamString(String rawValue) {
	  if (rawValue == null) {
	    return null;
	  }
	  if (filterXSS()) {
	   	rawValue = rawValue.replaceAll(XSS_REGEX, "");
	   	
	   	
	  }
	  if (filterSQL()) {
	    rawValue = rawValue.replaceAll(SQL_REGEX, "");
	  }
	  return rawValue;
	}
	
	
	@Override
	public Cookie[] getCookies() {
		Cookie[] existingCookies = super.getCookies();
		if(existingCookies != null) {
		  for(int i=0;i<existingCookies.length;++i) {
			  Cookie cookie = existingCookies[i];
			  cookie.setValue(filterParamString(cookie.getValue()));
		  }
		}
	  return existingCookies;
	}
	
	@Override
	public String getQueryString() {
	  return filterParamString(super.getQueryString());
	}
	
	protected boolean filterXSS() {
	  return filterXSS;
	}
	
	protected boolean filterSQL() {
	  return filterSQL;
	}
}


2)、WebXssEscapeFilterConfig类
/*
 * 文 件 名:  WebXssEscapeFilterConfig.java
 */
package com.zhgl.filter;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.zhgl.filter.defender.Defender;

/**
 * <一句话功能简述> <功能详细描述>
 * 
 * @author 姓名 工号
 * @version [版本号, 2015-12-2]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class WebXssEscapeFilterConfig
{
    
    private static final String DEFAULT_FILTER_RULE_FILENAME = "xss-servlet-filter-rule.xml";
    
    private Map<String, Map<String, WebXssEscapeFilterRule>> urlRuleSetMap = new HashMap();
    
    private Defender defaultDefender = null;
    
    public WebXssEscapeFilterConfig()
        throws IllegalStateException
    {
        this(DEFAULT_FILTER_RULE_FILENAME);
    }
    
    public WebXssEscapeFilterConfig(String filename)
        throws IllegalStateException
    {
        try
        {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename);
            Element rootElement = builder.parse(is).getDocumentElement();
            addDefaultInfo(rootElement);
            addUrlRuleSet(rootElement);
            System.out.println("配置文件初始化");
        }
        catch (Exception e)
        {
            throw new IllegalStateException("配置文件xss-servlet-filter-rule.xml读取异常.", e);
        }
    }
    
    private void addDefaultInfo(Element rootElement)
    {
        
        NodeList nodeList = rootElement.getElementsByTagName("default");
        if (nodeList.getLength() > 0)
        {
            Element defaultE = (Element)nodeList.item(0);
            nodeList = defaultE.getElementsByTagName("defender");
            if (nodeList.getLength() > 0)
            {
                String clazz = getTagContent((Element)nodeList.item(0), "class");
                try
                {
                    defaultDefender = (Defender)Class.forName(clazz.trim()).newInstance();
                }
                catch (Exception e)
                {
                    throw new IllegalStateException("defender初始失败!", e);
                }
                
            }
            
        }
        
    }
    
    private void addUrlRuleSet(Element rootElement)
    {
        NodeList nodeList = rootElement.getElementsByTagName("url-rule");
        for (int i = 0; (nodeList.getLength() > 0) && (i < nodeList.getLength()); i++)
        {
            Element element = (Element)nodeList.item(i);
            addUrlRule(element);
        }
    }
    
    private void addUrlRule(Element element)
    {
        Map paramRuleMap = null;
        String url = null;
        Element actionsElement = null;
        
        NodeList nodeList = element.getElementsByTagName("url");
        if (nodeList.getLength() > 0)
        {
            url = nodeList.item(0).getTextContent();
        }
        
        if (url != null)
        {
            nodeList = element.getElementsByTagName("actions");
            if (nodeList.getLength() > 0)
            {
                actionsElement = (Element)nodeList.item(0);
                if (actionsElement != null)
                {
                    
                    Map<String,WebXssEscapeFilterRule> ls = addActionParamsRule(actionsElement);
                    
                    if (ls.size() > 0)
                    {
                        urlRuleSetMap.put(url, ls);
                    }
                }
            }
        }
        
    }
    
    private Map<String, WebXssEscapeFilterRule> addActionParamsRule(Element element)
    {
        Map<String, WebXssEscapeFilterRule> ls = new HashMap<String, WebXssEscapeFilterRule>();
        NodeList nodeList = element.getElementsByTagName("action");
        for (int i = 0; (nodeList.getLength() > 0) && (i < nodeList.getLength()); i++)
        {
            Element element_t = (Element)nodeList.item(i);
            
            String actionName = element_t.getAttribute("name");
            String resultType = element_t.getAttribute("resultType");
            if (actionName == null || resultType == null)
            {
                continue;
            }
            
            List<String> params = new ArrayList<String>();
            NodeList nodeListt = element_t.getElementsByTagName("params");
            
            if (nodeListt.getLength() > 0)
            {
                Element element_params = (Element)nodeList.item(0);
                NodeList  nodeListtt = element_params.getElementsByTagName("param");
                for (int k = 0; (nodeListtt.getLength() > 0) && (k < nodeListtt.getLength()); k++)
                {
                    Element element_tt = (Element)nodeListtt.item(k);
                    String paramName = element_tt.getAttribute("name");
                    if (paramName == null)
                    {
                        continue;
                    }
                    params.add(paramName);
                }
            }
            if (params.size() == 0)
            {
                continue;
            }
            
            WebXssEscapeFilterRule rule = new WebXssEscapeFilterRule();
            rule.setActionName(actionName);
            rule.setResultType(resultType);
            rule.setParams(params);
            rule.setDefender(defaultDefender);
            ls.put(actionName, rule);
        }
        
        return ls;
        
    }
    
    private String getTagContent(Element eachElement, String tagName)
    {
        NodeList nodeList = eachElement.getElementsByTagName(tagName);
        if (nodeList.getLength() > 0)
        {
            return nodeList.item(0).getTextContent();
        }
        return "";
    }
    
    public Defender getDefaultDefender()
    {
        return this.defaultDefender;
    }
    
    public WebXssEscapeFilterRule getUrlParamRule(String url, String actionName, String paramName)
    {
        Map<String,WebXssEscapeFilterRule> listRule = (Map<String,WebXssEscapeFilterRule>)urlRuleSetMap.get(url);
        if(listRule == null){
            return null;
        }
        
       if( listRule.get(actionName) == null){
           return null;
       }else{
           WebXssEscapeFilterRule rule  = listRule.get(actionName) ;
           
          if( !rule.getParams().contains(paramName) ){
              return null;
          }else{
              return rule;
          }
       }
      
    }
    
    public WebXssEscapeFilterRule getUrlParamRule(String url, String actionName)
    {
        Map<String,WebXssEscapeFilterRule> listRule = (Map<String,WebXssEscapeFilterRule>)urlRuleSetMap.get(url);
        if(listRule == null){
            return null;
        }
        
       if( listRule.get(actionName) == null){
           return null;
       }else{
           WebXssEscapeFilterRule rule  = listRule.get(actionName) ;
           return rule;
       }
      
    }
    
}


3、WebXssEscapeFilterRule类
/*
 * 文 件 名:  WebXssEscapeFilterRule.java
 */
package com.zhgl.filter;

import java.util.List;

import com.zhgl.filter.defender.Defender;

/**
 * <一句话功能简述> <功能详细描述>
 * 
 * @author 姓名 工号
 * @version [版本号, 2015-12-2]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class WebXssEscapeFilterRule
{
    /**
     * action名称
     */
    private String actionName;
    /**
     * 返回类型
     */
    private String resultType;
    /**
     * 拦截器
     */
    private Defender defender;
    
    /**
     * 拦截的参数名称
     */
    private List<String> params;
    
    public String getActionName()
    {
        return actionName;
    }
    
    public void setActionName(String actionName)
    {
        this.actionName = actionName;
    }
    
    public String getResultType()
    {
        return resultType;
    }
    
    public void setResultType(String resultType)
    {
        this.resultType = resultType;
    }
    
    public List<String> getParams()
    {
        return params;
    }
    
    public void setParams(List<String> params)
    {
        this.params = params;
    }

    public Defender getDefender()
    {
        return defender;
    }

    public void setDefender(Defender defender)
    {
        this.defender = defender;
    }
    
}


4)、WebXssEscapeFilterUtil工具类
/*
 * 文 件 名:  WebXssEscapeFilterUtil.java
 */
package com.zhgl.filter;

/**
 * <一句话功能简述> <功能详细描述>
 * 
 * @author 姓名 工号
 * @version [版本号, 2015-12-2]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class WebXssEscapeFilterUtil
{
    
    private static WebXssEscapeFilterUtil xssUtil;
    
    private static WebXssEscapeFilterConfig config;
    
    private WebXssEscapeFilterUtil()
    {
        config = new WebXssEscapeFilterConfig();
    }
    
    public static WebXssEscapeFilterUtil getInstance()
    {
        return xssUtil;
    }
    
    public WebXssEscapeFilterRule getFilterRule(String url,String actionName){
        WebXssEscapeFilterRule urlRule = config.getUrlParamRule(url, actionName);
        return urlRule;
    }
    
 /*   public String doFilter(String url, String actionName, String paramName, String value)
    {
        WebXssEscapeFilterRule urlRule = config.getUrlParamRule(url, actionName, paramName);
        if (urlRule == null)
        {
            return value;
        }
        return urlRule.getDefender().doFilter(value);
    }*/
    
    static
    {
        try
        {
            xssUtil = new WebXssEscapeFilterUtil();
        }
        catch (Exception e)
        {
            throw new ExceptionInInitializerError(e);
        }
    }
    
}


5、默认的过滤规则接口类Defender.java
/*
 * 文 件 名:  Defender.java
 */
package com.zhgl.filter.defender;

/**
 * <一句话功能简述>
 * <功能详细描述>
 * 
 * @author  姓名 工号
 * @version  [版本号, 2015-12-2]
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
public abstract interface Defender
{
    public abstract Boolean doFilter(String paramString);
}


6、规则接口的实现类DefaultDefender.java
/*
 * 文 件 名:  defaultDefender.java
 */
package com.zhgl.filter.defender;

import java.util.regex.Pattern;

/**
 * <一句话功能简述>
 * <功能详细描述>
 * 
 * @author  姓名 工号
 * @version  [版本号, 2015-12-2]
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
public class DefaultDefender implements Defender
{
    private static final String XSS_REGEX = ".*[[<>]+|[']+|[\"]+|[/]+|[&]+|[\\\\]+].*";
    /**
     * 重载方法
     * @param paramString
     * @return
     */
    @Override
    public Boolean doFilter(String paramString)
    {
        Pattern pattern = Pattern.compile(XSS_REGEX); 
        if(!pattern.matcher(paramString).matches()){
            return true;
        }else{
            return false;
        }
    }
    
}



7、总结:实现思路主要通过过滤器将特殊字符进行过滤掉,在过滤器第一次执行的时候加载过滤规则并将保存到缓存中。