`

XSS跨站漏洞修复

阅读更多
避免XSS跨站漏洞的方法之一主要是将用户所提交的内容输入输出进行过滤,包括请求路径过滤与参数过滤。这里,我写一个过滤器专门处理XSS跨站漏洞,思路是将带有非法字符的请求转发到一个指定页面,将参数的非法字符过滤去除。

过滤器代码如下:
package com.eshore.itmp.model.web.security;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.regex.Pattern;

import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.filter.OncePerRequestFilter;

/**
 * XSS漏洞过滤器
 * 
 * @author ahomeeye
 * 
 */
public class XssFilter extends OncePerRequestFilter {
	private static Log logger = LogFactory.getLog(XssFilter.class);
	private String forwardUrl = "/login.jsp";

	@Override
	protected void doFilterInternal(HttpServletRequest req,
			HttpServletResponse res, FilterChain filterChain)
			throws ServletException, IOException {
		String uri = req.getRequestURI();
		logger.info("-------uri=" + uri);

		// 过滤请求的参数名和参数值
		XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(
				(HttpServletRequest) req);

		if (uri.contains("j_spring_security_check") && isContainSpecialChar(uri)) {// 判断uri是否合法
			logger.info("-------uri包含特殊字符 uri=" + xssRequest.getRequestURI());
			RequestDispatcher dispatcher = xssRequest
					.getRequestDispatcher(forwardUrl);
			dispatcher.forward(xssRequest, res);
		} else {
			filterChain.doFilter(xssRequest, res);// 执行其他过滤操作
		}

	}

	/**
	 * 判断字符串是否包含特殊字符
	 * 
	 * @param strVal
	 * @return
	 */
	public boolean isContainSpecialChar(String value) {
		String strVal = "";
		try {
			strVal = URLDecoder.decode(value, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			logger.error("URL解码错误", e);
		}
		boolean flag = false;
		if (match(".*?<script\\b.*?>*?</script>.*?", strVal)) {// //匹配js脚本字符串
			flag = true;
		} else if (match(".*?<.*?>.*?", strVal)) {// 匹配html标签字符串
			flag = true;
		}
		return flag;
	}

	/**
	 * 匹配正则表达式,大小写不敏感
	 * 
	 * @param regex
	 * @param input
	 * @return
	 */
	public boolean match(String regex, CharSequence input) {
		Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
		return p.matcher(input).matches();
	}

	public String getForwardUrl() {
		return forwardUrl;
	}

	public void setForwardUrl(String forwardUrl) {
		this.forwardUrl = forwardUrl;
	}

}

在xml文件中声明过滤器,配置过滤器链
	<beans:bean id="xssFilter" class="com.eshore.itmp.model.web.security.XssFilter" p:forwardUrl="/login.jsp">
	</beans:bean>
<beans:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
		<filter-chain-map path-type="ant">
			<filter-chain pattern="/kaptcha.validate" filters="none" />
			<filter-chain pattern="/services/**" filters="none" />
			<filter-chain pattern="/media/**" filters="none" />
			<filter-chain pattern="/css/**" filters="none" />
			<filter-chain pattern="/images/**" filters="none" />
			<filter-chain pattern="/js/**" filters="none" />
			<filter-chain pattern="/page/**" filters="none" />
			<filter-chain pattern="/My97DatePicker/**" filters="none" />
			<filter-chain pattern="/login.jsp" filters="none" />
			<filter-chain pattern="/phytopo/**" filters="none" />
			<filter-chain pattern="/relationView/**" filters="none" />
			<!-- add -->
			<filter-chain pattern="/oaLogin.do" filters="none" />
			<filter-chain pattern="/selection/**" filters="none" />
			<filter-chain pattern="/entity/**" filters="none" />
			<filter-chain pattern="/upload/**" filters="none" />

			<filter-chain pattern="/assessmentKpi/getExcelData.do**" filters="none" />

			<!-- add -->
			<filter-chain pattern="/logoutSuccess.jsp" filters="none" />
			<filter-chain pattern="/**" filters="
				xssFilter,
				securityContextPersistenceFilter,
				logoutFilter,
				usernamePasswordAuthenticationFilter,
				anonymousAuthenticationFilter,
				exceptionTranslationFilter,
				itmpCustomInterceptor,
				sysLogFilter" />
		</filter-chain-map>
	</beans:bean>


重写HttpServletRequest,覆盖一些方法
package com.eshore.itmp.model.web.security;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.regex.Pattern;

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

/**
 * 请求参数过滤器(修复跨站脚本漏洞)
 * 
 * @author ahomeeye
 * 
 */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

	HttpServletRequest orgRequest = null;

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

	/**
	 * 覆盖getParameter方法,将参数名和参数值都做xss过滤。<br/>
	 * 如果需要获得原始的值,则通过super.getParameterValues(name)来获取<br/>
	 * getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
	 */
	@Override
	public String getParameter(String name) {
		String value = super.getParameter(xssEncode(name));
		if (value != null) {
			value = xssEncode(value);
		}

		return value;
	}

	@Override
	public Object getAttribute(String name) {
		Object value = super.getAttribute(xssEncode(name));
		if (value instanceof String) {
			return xssEncode(value.toString());
		}

		return value;
	}

	/**
	 * 覆盖getHeader方法,将参数名和参数值都做xss过滤。<br/>
	 * 如果需要获得原始的值,则通过super.getHeaders(name)来获取<br/>
	 * getHeaderNames 也可能需要覆盖
	 */
	@Override
	public String getHeader(String name) {

		String value = super.getHeader(xssEncode(name));
		if (value != null) {
			value = xssEncode(value);
		}
		return value;
	}

	@Override
	public String getRequestURI() {

		String strVal = "";
		try {
			strVal = URLDecoder.decode(super.getRequestURI(), "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		String value = xssEncode(strVal);
		if (value != null) {
			value = xssEncode(value);
		}

		return value;
	}

	public String escape(String s) {
		StringBuilder sb = new StringBuilder(s.length() + 16);
		for (int i = 0; i < s.length(); i++) {
			char c = s.charAt(i);
			switch (c) {
			case '>':
				sb.append('>');// 全角大于号
				break;
			case '<':
				sb.append('<');// 全角小于号
				break;
			case '\'':
				sb.append('‘');// 全角单引号
				break;
			case '\"':
				sb.append('“');// 全角双引号
				break;
			case '\\':
				sb.append('\');// 全角斜线
				break;
			case '%':
				sb.append('%'); // 全角冒号
				break;
			case ';':
				sb.append(';'); // 全角分号
				break;
			default:
				sb.append(c);
				break;
			}

		}
		return sb.toString();
	}

	/**
	 * 将容易引起xss漏洞的半角字符直接替换成全角字符
	 * 
	 * @param s
	 * @return
	 */
	public String xssEncode(String s) {
		if (s == null || s.isEmpty()) {
			return s;
		}

		String result = stripXSS(s);
		if (null != result) {
			result = escape(result);
		}

		return result;
	}

	private String stripXSS(String value) {
		if (value != null) {
			// NOTE: It's highly recommended to use the ESAPI library and
			// uncomment the following line to
			// avoid encoded attacks.
			// value = ESAPI.encoder().canonicalize(value);
			// Avoid null characters
			value = value.replaceAll("", "");
			// 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("");
			scriptPattern = Pattern.compile("src[\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("");

			scriptPattern = Pattern.compile("<iframe>(.*?)</iframe>",
					Pattern.CASE_INSENSITIVE);
			value = scriptPattern.matcher(value).replaceAll("");

			scriptPattern = Pattern.compile("</iframe>",
					Pattern.CASE_INSENSITIVE);
			value = scriptPattern.matcher(value).replaceAll("");

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

	/**
	 * 获取最原始的request
	 * 
	 * @return
	 */
	public HttpServletRequest getOrgRequest() {
		return orgRequest;
	}

	@Override
	public HttpServletRequest getRequest() {
		return orgRequest;
	}

	/**
	 * 获取最原始的request的静态方法
	 * 
	 * @return
	 */
	public static HttpServletRequest getOrgRequest(HttpServletRequest req) {
		if (req instanceof XssHttpServletRequestWrapper) {
			return ((XssHttpServletRequestWrapper) req).getOrgRequest();
		}

		return req;
	}

}


最后,给个页面表单例子:
<script type="text/javascript">
		function setPass(originId,decId){
			var orginName = window.parent.document.getElementById('orginName').value;
			var newName = strEnc(orginName,'itmp','des','encrypt');
			window.parent.document.getElementById('userId').value = newName;
			
			var orginPass = window.parent.document.getElementById(originId).value;
			var newPass = strEnc(orginPass,'itmp','des','encrypt');
			//alert('newPass=' + newPass + ' pass='+strDec(newPass,'itmp','des','encrypt'));
			window.parent.document.getElementById(decId).value = newPass;
		}
	</script>

<form id="form" name="form" action="${ctx}/j_spring_security_check" method="post">
	<table width="100%" border="0" cellspacing="0" cellpadding="0">
 	 <tr>
     	<td width="20%" height="10" class="black14" align="center" valign="middle"></td>
     	<td colspan="2" align="left">
        	<div class="error${param.error==true?'':'hide'}" style="color:red;">
		${sessionScope['SPRING_SECURITY_LAST_EXCEPTION'].message}
		</div>
    	</td>
    </tr>
   <tr>
     <td width="20%" height="35" class="black14">用户名</td>
     <td colspan="2" align="left"><label >
       <input type="text" id="orginName" value="${sessionScope['SPRING_SECURITY_LAST_USERNAME']}" class="input" />
       <input type="hidden" id="userId" name="j_username" value="" class="input"/>
     </label></td>
   </tr>
   <tr>
     <td height="35" class="black14">密&nbsp;&nbsp;&nbsp;码</td>
     <td colspan="2" align="left"><label >
       <input type="password" id="orginPass" class="input" onblur="setPass('orginPass','password');"/>
       <input type="hidden" name="j_password" id="password" class="input"/>
     </label></td>
   </tr>
   <tr>
     <td height="35" class="black14">验证码</td>
     <td width="37%" align="left"><label>
       <input type="text" name="validateCode" class="input2"/>
     </label></td>
     <td width="43%" align="left">
     	<img onclick="this.src='kaptcha.validate'" src="kaptcha.validate" width="77" height="28" />
     </td>
   </tr>
   <tr>
     <td height="93" colspan="3" align="center">
     	<a href="#">
     		<input type="image" src="${ctx}/css/remake/images/button_login.gif" width="111" height="36" border="0" />
     	</a>
     </td>
   </tr>
 </table>
</form>


参考网址:
http://yunjiechao-163-com.iteye.com/blog/1973803
http://www.cnblogs.com/wuhuacong/archive/2013/04/15/3022011.html
分享到:
评论

相关推荐

    XSS跨站脚本攻击漏洞修复方法

    NULL 博文链接:https://gqsunrise.iteye.com/blog/2214704

    修复swfupload2.5版存在的XSS跨站攻击漏洞

    修复swfupload2.5版存在的XSS跨站攻击漏洞,测试无错误版本。

    xss漏洞jar.rar

    跨站脚本(Cross site script,简称xss)是一种“HTML注入”,由于攻击的脚本多数时候是跨域的,所以称之为“跨域脚本”。 我们常常听到“注入”...可以通过导入以下两个jar,通过配置实现xss漏洞修复,无需修改代码

    XSS漏洞解决方案实例

    跨网站脚本(Cross-site scripting,通常简称为XSS或跨站脚本或跨站脚本攻击)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类...

    第28天:WEB漏洞-XSS跨站之WAF绕过及安全修复1

    WEB 漏洞-XSS 跨站之 WAF 绕过及安全修复#常规 WAF 绕过思路标签语法替换特殊符号干扰提交方式更改垃圾数据溢出加密解密算法结合其他漏洞绕过#自动化

    修补跨站脚本攻击漏洞 asp版 v1.0

    可以修补动网论坛等asp建的网站的跨站脚本攻击漏洞,修护XSS漏洞,此为asp版的,还有php版、aspx版,可以在本站下载 详情请参看:http://www.lbhao.com/detaile_ok-5-833.html

    非富文本XSS漏洞预防和修复代码规范

    XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意用户的特殊目的

    anti-xss:AntiAntiXSS | 通过PHP防止跨站点脚本(XSS)

    :Japanese_secret_button: 反XSS “跨站点脚本(XSS)是一种通常在Web应用程序中发现的计算机安全漏洞。XSS使攻击者能够将客户端脚本注入到其他用户查看的网页中。跨站点脚本漏洞可能被攻击者用来绕过相同原产地策略...

    ASP.NET跨站脚本攻击漏洞修补文件aspx版 v1.0

    跨站脚本攻击漏洞修补文件aspx版,使用方法:1.将App_Code目录拷贝到web根目录  假如已经存在App_Code目录,那直接把App_Code目录里的360safe.cs文件拷贝到当前的App_Code目录即可。  2.将Global.asax文件拷贝到web...

    JSP安全开发之XSS漏洞详解

    XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意脚本代码,而程序对于用户输入内容未过滤,当用户浏览该页之时,嵌入其中Web里面的脚本代码会被执行,从而达到恶意攻击用户...

    WEB安全漏洞集锦

    2. 跨站脚本(XSS)漏洞 6 漏洞描述 6 漏洞危害 6 解决方案 7 代码示例 7 3. HTTP header注入漏洞 8 漏洞描述 8 修复建议 8 4. 目录遍历漏洞 8 漏洞描述 8 解决方案 8 5. 文件包含漏洞 9 漏洞描述 9 漏洞危害 9 解决...

    salemanm.zip

    问题描述:防止XSS跨站漏洞 改造:修改项目框架的web.xml文件,增加过滤器filter对请求进行拦截过滤; 检查lib目录下nanny-0.1.jar是否存在 部署完,需要重启bssframe

    Web安全测试之XSS实例讲解

    XSS 全称(Cross Site Scripting) 跨站脚本攻击, 是Web程序中最常见的漏洞。指攻击者在网页中嵌入客户端脚本(例如JavaScript), 当用户浏览此网页时,脚本就会在用户的浏览器上执行,从而达到攻击者的目的. 比如获取...

    SiteServer CMS v4.1.1601

    2015年09月09日SiteServer CMS 4.11、新增用户中心2、新增用户投稿系统3、新增内容跨站转发功能4、新增管理内容组内容功能5、新增电视剧内容...部分xss跨站攻击漏洞修复2、异步生成数据太多引起网站反映速度变慢3、stl...

    修补跨站脚本攻击漏洞 aspx版源代码

    可以修补动网论坛等aspx建的网站的跨站脚本攻击漏洞,修护XSS漏洞,此为aspx版的,还有asp版、php版,可以在本站下载 详情请参看:http://www.lbhao.com/detaile_ok-5-833.html

    Web安全性测试之XSS

    全称(CrossSiteScripting)跨站脚本攻击,是Web程序中最常见的漏洞。指攻击者在网页中嵌入客户端脚本(例如JavaScript), 当用户浏览此网页时,脚本就会在用户的浏览器上执行,从而达到攻击者的目的.比如获取用户的...

    xss-demo-react-mobx-todo:该项目旨在演示跨站点脚本攻击以及​​如何修复xss漏洞

    修复XSS问题 步骤1: 在package.json添加以下行"jsesc": "^2.3.0"依赖项中的"jsesc": "^2.3.0"并执行npm i (或者) 安装jsesc使用npm install jsesc 第2步: 在src/client.js替换const initialState = window....

    Web安全深度剖析(张柄帅)

    7.5 修复XSS跨站漏洞 151 7.5.1 输入与输出 151 7.5.2 HttpOnly 158 7.6 小结 160 第8章 命令执行漏洞 161 8.1 OS命令执行漏洞示例 161 8.2 命令执行模型 162 8.2.1 PHP命令执行 163 8.2.2 Java命令执行 165 8.3 ...

    Yii2的XSS攻击防范策略分析

    XSS 漏洞修复 原则: 不相信客户输入的数据 注意: 攻击代码不一定在[removed][removed]中 ① 将重要的cookie标记为http only, 这样的话Javascript 中的[removed]语句就不能获取到cookie了. ② 只允许用户输入我们...

    蝉知企业门户系统 企业网站源码

    软件简介: 蝉知门户系统(changezhiEPS)是一款开源免费的...新增防xss跨站攻击处理 优化后台区块管理操作体验 修复通过字段可进行sql注入的漏洞 修复产品数据结构bug 修复繁体版安装失败bug 修复论坛帖子隐藏显示bug

Global site tag (gtag.js) - Google Analytics