java 防止 XSS 攻击的常用方法总结.
java web应用程序防止 csrf 攻击的方法,参考这里 java网页程序采用 spring 防止 csrf 攻击. ,但这只是攻击的一种方式,还有其他方式,比如今天要记录的 XSS 攻击, XSS 攻击的专业解释,可以在网上搜索一下,参考百度百科的解释 http://baike.baidu.com/view/2161269.htm, 但在实际的应用中如何去防止这种攻击呢,下面给出几种办法.
1. 自己写 filter 拦截来实现,但要注意的时,在WEB.XML 中配置 filter 的时候,请将这个 filter 放在第一位.
2. 采用开源的实现 ESAPI library ,参考网址:https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API
3. 可以采用spring 里面提供的工具类来实现.
一, 第一种方法。
配置过滤器
publicclassXSSFilterimplementsFilter{ @Override publicvoid init(FilterConfig filterConfig)throwsServletException{ } @Override publicvoid destroy(){ } @Override publicvoid doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throwsIOException,ServletException{ chain.doFilter(newXSSRequestWrapper((HttpServletRequest) request), response); }}
再实现 ServletRequest 的包装类
import java.util.regex.Pattern;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;publicclassXSSRequestWrapperextendsHttpServletRequestWrapper{ publicXSSRequestWrapper(HttpServletRequest servletRequest){ super(servletRequest); } @Override publicString[] getParameterValues(String parameter){ String[] values =super.getParameterValues(parameter); if(values ==null){ returnnull; } int count = values.length; String[] encodedValues =newString[count]; for(int i =0; i < count; i++){ encodedValues[i]= stripXSS(values[i]); } return encodedValues; } @Override publicString getParameter(String parameter){ String value =super.getParameter(parameter); return stripXSS(value); } @Override publicString getHeader(String name){ String value =super.getHeader(name); return stripXSS(value); } privateString 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("(.*?)",Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); // Avoid anything in a src="http://www.yihaomen.com/article/java/..." 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 tag scriptPattern =Pattern.compile("",Pattern.CASE_INSENSITIVE); value = scriptPattern.matcher(value).replaceAll(""); // Remove any lonesome tag scriptPattern =Pattern.compile("",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; }}
例子中注释的部分,就是采用 ESAPI library 来防止XSS攻击的,推荐使用.
当然,我还看到这样一种办法,将所有的编程全角字符的解决方式,但个人觉得并没有上面这种用正则表达式替换的好
privatestaticString xssEncode(String s){ if(s ==null|| s.equals("")){ return s; } StringBuilder sb =newStringBuilder(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('\\'); sb.append('\''); sb.append('\\'); sb.append('\''); break; case'\"': sb.append('\\'); 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(); }
当然,还有如下更简单的方式:
privateString cleanXSS(String value){ //You'll need to remove the spaces from the html entities below value = value.replaceAll("<","& lt;").replaceAll(">","& gt;"); value = value.replaceAll("\\(","& #40;").replaceAll("\\)","& #41;"); value = value.replaceAll("'","& #39;"); value = value.replaceAll("eval\\((.*)\\)",""); value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']","\"\""); value = value.replaceAll("script",""); return value; }
在后台或者用spring 如何实现呢:
首先添加一个jar包:commons-lang-2.5.jar ,然后在后台调用这些函数:
StringEscapeUtils.escapeHtml(string);StringEscapeUtils.escapeJavaScript(string);StringEscapeUtils.escapeSql(string);
当然,我记得在spring 里面好像有一个 HtmlUtils.htmlEscape , 同样可以做到 过滤 XSS 攻击。从上面的介绍可以看出,防止 XSS 攻击并不难,就是要小心。
===============================================================
在apache commons-lang(2.3以上版本)中为我们提供了一个方便做转义的工具类,主要是为了防止sql注入,xss注入攻击的功能。总共提供了以下几个方法:
1.escapeSql 提供sql转移功能,防止sql注入攻击,例如典型的万能密码攻击' ' or 1=1 ' '
StringBuffer sql = new StringBuffer("select key_sn,remark,create_date from tb_selogon_key where 1=1 "); if(!CommUtil.isEmpty(keyWord)){ sql.append(" and like '%" + StringEscapeUtils.escapeSql(keyWord) + "%'"); }
StringBuffer sql = new StringBuffer("select key_sn,remark,create_date from tb_selogon_key where 1=1 "); if(!CommUtil.isEmpty(keyWord)){ sql.append(" and like '%" + StringEscapeUtils.escapeSql(keyWord) + "%'"); }
2.escapeHtml /unescapeHtml 转义/反转义html脚本
System.out.println(StringEscapeUtils.escapeHtml("<a>dddd</a>")); 输出结果为:<a>dddd</a>
System.out.println(StringEscapeUtils.escapeHtml("<a>dddd</a>")); 输出结果为:<a>dddd</a>
System.out.println(StringEscapeUtils.unescapeHtml("<a>dddd</a>")); 输出为:<a>ddd</a>
System.out.println(StringEscapeUtils.unescapeHtml("<a>dddd</a>")); 输出为:<a>ddd</a>
3.escapeJavascript/unescapeJavascript 转义/反转义js脚本
System.out.println(StringEscapeUtils.escapeJavaScript("<script>alert('1111')</script>")); 输出为:<script>alert('111')</script>
System.out.println(StringEscapeUtils.escapeJavaScript("<script>alert('1111')</script>")); 输出为:<script>alert('111')</script>
4.escapeJava/unescapeJava 把字符串转为unicode编码
System.out.println(StringEscapeUtils.escapeJava("中国")); 输出为:用escapeJava方法转义之后的字符串为:/u4E2D/u56FD/u5171/u4EA7/u515A
==============================================
apache工具包common-lang中有一个很有用的处理字符串的工具类,其中之一就是StringEscapeUtils,这个工具类是在2.3版本以上加上的去的,利用它能很方便的进行html,xml,java等的转义与反转义,而且还能对关键字符串进行处理预防SQL注入,不过好像common-lang3.0以后我看着好像没这个处理SQL语句的方法了,想用的话前提时引入对应的jar包,以下为它的部分方法:
它的方法,全是静态,直接用类调用即可,下边来根据代码看看它们几个的用法和效果,一看一目了然:
package stringescapeutils; import org.apache.commons.lang.StringEscapeUtils; public class StringEscapeUtilsTest { public static void main(String args[]){ String sql="1' or '1'='1"; System.out.println("防SQL注入:"+StringEscapeUtils.escapeSql(sql)); //防SQL注入 System.out.println("转义HTML,注意汉字:"+StringEscapeUtils.escapeHtml("<font>chen磊 xing</font>")); //转义HTML,注意汉字 System.out.println("反转义HTML:"+StringEscapeUtils.unescapeHtml("<font>chen磊 xing</font>")); //反转义HTML System.out.println("转成Unicode编码:"+StringEscapeUtils.escapeJava("陈磊兴")); //转义成Unicode编码 System.out.println("转义XML:"+StringEscapeUtils.escapeXml("<name>陈磊兴</name>")); //转义xml System.out.println("反转义XML:"+StringEscapeUtils.unescapeXml("<name>陈磊兴</name>")); //转义xml } }
输入结果:
防SQL注入:1'' or ''1''=''1 转义HTML,注意汉字:<font>chen磊 xing</font> 反转义HTML:<font>chen磊 xing</font> 转成Unicode编码:\u9648\u78CA\u5174 转义XML:<name>陈磊兴</name> 反转义XML:<name>陈磊兴</name>
http://blog.csdn.net/chenleixing/article/details/43456987
http://www.cnblogs.com/thinkpad/p/4837841.html
http://blog.csdn.net/joeyon1985/article/details/43527987