解决XSS攻击漏斗的过滤器
来源:互联网 发布:大数据研发工程师 编辑:程序博客网 时间:2024/06/08 14:00
新上线的系统被测试出有XSS攻击漏洞,做的过程中一直没有考虑到这个问题。被查出这个问题,通过从网上查阅的资料,将解决方法记录一下,以备不时之需。
- 什么是XSS
XSS攻击是Web攻击中最常见的攻击方法之一,它是通过对网页注入可执行代码且成功地被浏览器
执行,达到攻击的目的,形成了一次有效XSS攻击,一旦攻击成功,它可以获取用户的联系人列
表,然后向联系人发送虚假诈骗信息,可以删除用户的日志等等,有时候还和其他攻击方式同时实
施比如SQL注入攻击服务器和数据库、Click劫持、相对链接劫持等实施钓鱼,它带来的危害是巨
大的,是web安全的头号大敌。
- 攻击的条件
实施XSS攻击需要具备两个条件:
一、需要向web页面注入恶意代码;二、这些恶意代码能够被浏览器成功的执行。
- XSS攻击能做些什么
窃取cookies,读取目标网站的cookie发送到黑客的服务器上,如下面的代码;
读取用户未公开的资料,如果:邮件列表或者内容、系统的客户资料,联系人列表等等
- XSS攻击的过程
- 怎么解决
我的解决办法是加过滤器转义特殊字符。
首先写好过滤器,具体代码如下:
XssSecurityFilter.java
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 org.apache.log4j.Logger;public class XssSecurityFilter implements Filter {protected final Logger log = Logger.getLogger(this.getClass());public void init(FilterConfig config) throws ServletException {if (log.isInfoEnabled()) {log.info("XSSSecurityFilter Initializing ");}}/** * 销毁操作 */public void destroy() {if (log.isInfoEnabled()) {log.info("XSSSecurityFilter destroy() end");}}public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;XssHttpRequestWrapper xssRequest = new XssHttpRequestWrapper(httpRequest);httpRequest = XssSecurityManager.wrapRequest(xssRequest);chain.doFilter(xssRequest, response);}}XssHttpRequestWrapper.javaimport java.io.UnsupportedEncodingException;import java.util.Map;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;/** * @author * @date * @describe 主要是对参数进行xss过滤,替换原始的request的getParameter相关功能 线程不安全 * */public class XssHttpRequestWrapper extends HttpServletRequestWrapper {protected Map parameters;/** * 封装http请求 * * @param request */public XssHttpRequestWrapper(HttpServletRequest request) {super(request);}@Overridepublic void setCharacterEncoding(String enc)throws UnsupportedEncodingException {super.setCharacterEncoding(enc);// 当编码重新设置时,重新加载重新过滤缓存。refiltParams();}void refiltParams() {parameters = null;}@Overridepublic String getParameter(String string) {String strList[] = getParameterValues(string);if (strList != null && strList.length > 0)return strList[0];elsereturn null;}@Overridepublic String[] getParameterValues(String string) {if (parameters == null) {paramXssFilter();}return (String[]) parameters.get(string);}@Overridepublic Map getParameterMap() {if (parameters == null) {paramXssFilter();}return parameters;}/** * * 校验参数,若含xss漏洞的字符,进行替换 */private void paramXssFilter() {parameters = getRequest().getParameterMap();XssSecurityManager.filtRequestParams(parameters, this.getServletPath());}}XssSecurityManager.javaimport java.io.InputStream;import java.util.ArrayList;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Set;import java.util.regex.Pattern;import javax.servlet.http.HttpServletRequest;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import org.apache.log4j.Logger;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;/** * @author * @date * @describe 安全过滤配置管理类,统一替换可能造成XSS漏洞的字符为中文字符 */ public class XssSecurityManager {private static Logger log = Logger.getLogger(XssSecurityManager.class); // 危险的javascript:关键字j av a script private final static Pattern[] DANGEROUS_TOKENS = new Pattern[] { Pattern .compile("^j\\s*a\\s*v\\s*a\\s*s\\s*c\\s*r\\s*i\\s*p\\s*t\\s*:", Pattern.CASE_INSENSITIVE) }; // javascript:替换字符串(全角中文字符) private final static String[] DANGEROUS_TOKEN_REPLACEMENTS = new String[] { "JAVASCRIPT:" }; // 非法的字符集 private static final char[] INVALID_CHARS = new char[] { '<', '>', '\'', '\"', '\\' }; // 统一替换可能造成XSS漏洞的字符为全角中文字符 private static final char[] VALID_CHARS = new char[] { '<', '>', '’', '“', '\' }; // 开启xss过滤功能开关 public static boolean enable=false; // url-patternMap(符合条件的url-param进行xss过滤)<String ArrayList> public static Map urlPatternMap = new HashMap(); private static HashSet excludeUris=new HashSet(); private XssSecurityManager() { // 不可被实例化 } static { init(); } private static void init() { try { String xssConfig = "/xss_security_config.xml"; if(log.isDebugEnabled()){ log.debug("XSS config file["+xssConfig+"] init..."); } InputStream is = XssSecurityManager.class .getResourceAsStream(xssConfig); if (is == null) { log.warn("XSS config file["+xssConfig+"] not found."); }else{ // 初始化过滤配置文件 initConfig(is); log.info("XSS config file["+xssConfig+"] init completed."); } } catch (Exception e) { log.error("XSS config file init fail:"+e.getMessage(), e); } } private static void initConfig(InputStream is) throws Exception{ DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); DocumentBuilder builder=factory.newDocumentBuilder(); Element root = builder.parse(is).getDocumentElement(); //------------------- NodeList nl=root.getElementsByTagName("enable"); Node n=null; if(nl!=null && nl.getLength()>0){ n=((org.w3c.dom.Element)nl.item(0)).getFirstChild(); } if(n!=null){ enable = new Boolean(n.getNodeValue().trim()).booleanValue(); } log.info("XSS switch="+enable); //------------------------- nl=root.getElementsByTagName("filter-mapping"); NodeList urlPatternNodes=null; if(nl!=null && nl.getLength()>0){ Element el=(Element)nl.item(0); urlPatternNodes=el.getElementsByTagName("url-pattern"); //----------------------------------------------------- NodeList nl2=el.getElementsByTagName("exclude-url"); if(nl2!=null && nl2.getLength()>0){ for(int i=0;i<nl2.getLength();i++){ Element e=(Element)urlPatternNodes.item(i); Node paramNode=e.getFirstChild(); if(paramNode!=null){ String paramName=paramNode.getNodeValue().trim(); if(paramName.length()>0){ excludeUris.add(paramName.toLowerCase()); } } } } } //---------------------- if(urlPatternNodes!=null && urlPatternNodes.getLength()>0){ for(int i=0;i<urlPatternNodes.getLength();i++){ Element e=(Element)urlPatternNodes.item(i); String urlPattern=e.getAttribute("value"); if(urlPattern!=null && (urlPattern=urlPattern.trim()).length()>0){ List filtParamList = new ArrayList(2); if(log.isDebugEnabled()){ log.debug("Xss filter mapping:"+urlPattern); } //------------------------------- NodeList temp=e.getElementsByTagName("include-param"); if(temp!=null && temp.getLength()>0){ for(int m=0;m<temp.getLength();m++){ Node paramNode=(temp.item(m)).getFirstChild(); if(paramNode!=null){ String paramName=paramNode.getNodeValue().trim(); if(paramName.length()>0){ filtParamList.add(paramName); } } } } //一定得将url转换为小写 urlPatternMap.put(urlPattern.toLowerCase(), filtParamList); } } } //---------------------- }public static HttpServletRequest wrapRequest(HttpServletRequest httpRequest){ if(httpRequest instanceof XssHttpRequestWrapper){ // log.info("httpRequest instanceof XssHttpRequestWrapper"); //include/forword指令会重新进入此Filter XssHttpRequestWrapper temp=(XssHttpRequestWrapper)httpRequest; //include指令会增加参数,这里需要清理掉缓存 temp.refiltParams(); return temp; }else{ // log.info("httpRequest is not instanceof XssHttpRequestWrapper"); return httpRequest; } }
public static List getFiltParamNames(String url){ //获取需要xss过滤的参数 url = url.toLowerCase(); List paramNameList = (ArrayList) urlPatternMap.get(url); if(paramNameList==null || paramNameList.size()==0){ return null; } return paramNameList; } public static void filtRequestParams(Map params,String servletPath){ long t1=System.currentTimeMillis(); //得到需要过滤的参数名列表,如果列表是空的,则表示过滤所有参数 List filtParamNames=XssSecurityManager.getFiltParamNames(servletPath); filtRequestParams(params, filtParamNames); } public static void filtRequestParams(Map params,List filtParamNames){ // 获取当前参数集 Set parameterNames = params.keySet(); Iterator it = parameterNames.iterator(); //得到需要过滤的参数名列表,如果列表是空的,则表示过滤所有参数 while (it.hasNext()) { String paramName = (String) it.next(); if(filtParamNames==null || filtParamNames.contains(paramName) ){ String[] values = (String[])params.get(paramName); proceedXss(values); } } } /** * 对参数进行防止xss漏洞处理 * * @param value * @return */ private static void proceedXss(String[] values) { for (int i = 0; i < values.length; ++i) { String value = values[i]; if (!isNullStr(value)) { values[i] = replaceSpecialChars(values[i]); } } } /** * 替换非法字符以及危险关键字 * * @param str * @return */ private static String replaceSpecialChars(String str) { for (int j = 0; j < INVALID_CHARS.length; ++j) { if (str.indexOf(INVALID_CHARS[j]) >= 0) { str = str.replace(INVALID_CHARS[j], VALID_CHARS[j]); } } str=str.trim(); for (int i = 0; i < DANGEROUS_TOKENS.length; ++i) { str = DANGEROUS_TOKENS[i].matcher(str).replaceAll( DANGEROUS_TOKEN_REPLACEMENTS[i]); } return str; } /** * 判断是否为空串,建议放到某个工具类中 * * @param value * @return */ private static boolean isNullStr(String value) { return value == null || value.trim().length()==0; } public static void main(String args[]) throws Exception{ Map datas=new HashMap(); String paramName="test"; datas.put(paramName,new String[]{ "Javascript:<script>alert('yes');</script>"}); filtRequestParams(datas,"/test/sample.do"); System.out.println(((String[])datas.get(paramName))[0]); } }然后配置Web.xml文件:<filter> <filter-name>XSSFiler</filter-name> <filter-class>com.fh.filter.XssSecurityFilter</filter-class> </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> <filter-mapping> <filter-name>XSSFiler</filter-name> <url-pattern>*.screen</url-pattern> </filter-mapping> <filter-mapping> <filter-name>XSSFiler</filter-name> <url-pattern>*.shtml</url-pattern> </filter-mapping> <filter-mapping> <filter-name>XSSFiler</filter-name> <servlet-name>dispatcher</servlet-name> </filter-mapping>
- 解决前输入的非法字符串展示如下(输入的企业名称是[<script>alert('1111');</script>]):
- 加入过滤器后,输入的非法字符展示如:
- XSS过滤加入后引发的问题如下:
由于系统中附件的上传下载封装了共同页面,使用了<jsp:include>和<jsp:param>标签,XSS过滤加入之后,<jsp:param>的参数就传递不到共通页面。
根据分析查找,可能是过滤器中一下代码影响:
public static HttpServletRequest wrapRequest(HttpServletRequest httpRequest){ if(httpRequest instanceof XssHttpRequestWrapper){ // log.info("httpRequest instanceof XssHttpRequestWrapper"); //include/forword指令会重新进入此Filter XssHttpRequestWrapper temp=(XssHttpRequestWrapper)httpRequest; //include指令会增加参数,这里需要清理掉缓存 temp.refiltParams(); return temp; }else{ // log.info("httpRequest is not instanceof XssHttpRequestWrapper"); return httpRequest; } }httpRequest = XssSecurityManager.wrapRequest(xssRequest);但是将上述代码去掉后,依然没有解决问题,目前还在百思不得其解中,如果有哪位高手经过,可以指点一下。。。。。。
阅读全文
0 0
- 解决XSS攻击漏斗的过滤器
- 解决XSS攻击漏斗的过滤器解决方案(二)
- XSS攻击过滤器
- XSS攻击过滤器
- 字符过滤器和防止XSS攻击,SQL注入的过滤器
- 富文本编辑器 xss 攻击的解决
- python的flask解决xss攻击漏洞
- Servlet Filter 技术防止XSS攻击的过滤器例子
- springMVC利用过滤器防止xss攻击
- 使用filter解决xss攻击
- XSS攻击的过滤
- XSS攻击的防范
- XSS攻击的防范
- XSS攻击的原理
- XSS攻击的原理
- 简单的XSS攻击
- XSS攻击的原理
- XSS攻击的危害
- Java中 outer 标签的使用
- 通过java调用Http接口上传图片到服务器
- Oracle存储过程基本语法介绍
- django+spider简易爬虫搭建
- Parameter 'id' not found. Available parameters are [0, 1, 2, param3, param1, param2]
- 解决XSS攻击漏斗的过滤器
- 两直线四坐标点判断相交并求交点
- 基于maven+spring+springmvc+mabtis的websocket聊天功能和界面
- centos/ubuntu环境下hadoop伪分布式搭建
- linux 安装工具
- dB、dBm、dBw和w的换算关系
- 标签的显示模式
- C语言函数的递归调用
- bzoj 1260: [CQOI2007]涂色paint(区间DP)