java http url xss,XSS 防护方法总结

1. XSS攻击原理javascript

XSS原称为CSS(Cross-Site Scripting),由于和层叠样式表(Cascading Style Sheets)重名,因此改称为XSS(X通常有未知的含义,还有扩展的含义)。XSS攻击涉及到三方:攻击者,用户,web server。用户是经过浏览器来访问web server上的网页,XSS攻击就是攻击者经过各类办法,在用户访问的网页中插入本身的脚本,让其在用户访问网页时在其浏览器中进行执行。攻击者经过插入的脚本的执行,来得到用户的信息,好比cookie,发送到攻击者本身的网站(跨站了)。因此称为跨站脚本攻击。XSS能够分为反射型XSS和持久性XSS,还有DOM Based XSS。(一句话,XSS就是在用户的浏览器中执行攻击者本身定制的脚本。)php

1.1 反射型XSShtml

反射性XSS,也就是非持久性XSS。用户点击攻击连接,服务器解析后响应,在返回的响应内容中出现攻击者的XSS代码,被浏览器执行。一来一去,XSS攻击脚本被web server反射回来给浏览器执行,因此称为反射型XSS。java

特色:nginx

1> XSS攻击代码非持久性,也就是没有保存在web server中,而是出如今URL地址中;web

2> 非持久性,那么攻击方式就不一样了。通常是攻击者经过邮件,聊天软件等等方式发送攻击URL,而后用户点击来达到攻击的;ajax

1.2持久型XSSsql

区别就是XSS恶意代码存储在web server中,这样,每个访问特定网页的用户,都会被攻击。apache

特色:c#

1> XSS攻击代码存储于web server上;

2> 攻击者,通常是经过网站的留言、评论、博客、日志等等功能(全部可以向web server输入内容的地方),将攻击代码存储到web server上的;

有时持久性XSS和反射型XSS是同时使用的,好比先经过对一个攻击url进行编码(来绕过xss filter),而后提交该web server(存储在web server中), 而后用户在浏览页面时,若是点击该url,就会触发一个XSS攻击。固然用户点击该url时,也可能会触发一个CSRF(Cross site request forgery)攻击。

1.3 DOM based XSS

基于DOM的XSS,也就是web server不参与,仅仅涉及到浏览器的XSS。好比根据用户的输入来动态构造一个DOM节点,若是没有对用户的输入进行过滤,那么也就致使XSS攻击的产生。过滤能够考虑采用esapi4js。

参见:http://www.freebuf.com/articles/web/29177.html , http://www.zhihu.com/question/26628342/answer/33504799

2.XSS 存在的缘由

XSS 存在的根本缘由是,对URL中的参数,对用户输入提交给web server的内容,没有进行充分的过滤。若是咱们可以在web程序中,对用户提交的URL中的参数,和提交的全部内容,进行充分的过滤,将全部的不合法的参数和输入内容过滤掉,那么就不会致使“在用户的浏览器中执行攻击者本身定制的脚本”。

可是,其实充分而彻底的过滤,其实是没法实现的。由于攻击者有各类各样的神奇的,你彻底想象不到的方式来绕过服务器端的过滤,最典型的就是对URL和参数进行各类的编码,好比escape, encodeURI, encodeURIComponent, 16进制,10进制,8进制,来绕过XSS过滤。那么咱们如何来防护XSS呢?

3.XSS 攻击的防护

XSS防护的整体思路是:对输入(和URL参数)进行过滤,对输出进行编码。

也就是对提交的全部内容进行过滤,对url中的参数进行过滤,过滤掉会致使脚本执行的相关内容;而后对动态输出到页面的内容进行html编码,使脚本没法在浏览器中执行。虽然对输入过滤能够被绕过,可是也仍是会拦截很大一部分的XSS攻击。

3.1 对输入和URL参数进行过滤(白名单和黑名单)

下面贴出一个经常使用的XSS filter的实现代码:

75d6c0430f8d4da99c4fa5d0.html

public class XssFilter implements Filter {

public void init(FilterConfig config) throws ServletException {}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

throws IOException, ServletException {

XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest)request);

chain.doFilter(xssRequest, response);

}

public void destroy() {}

}

75d6c0430f8d4da99c4fa5d0.html

75d6c0430f8d4da99c4fa5d0.html

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

HttpServletRequest orgRequest = null;

public XssHttpServletRequestWrapper(HttpServletRequest request) {

super(request);

orgRequest = request;

}

/**

* 覆盖getParameter方法,将参数名和参数值都作xss过滤。

* 若是须要得到原始的值,则经过super.getParameterValues(name)来获取

* getParameterNames,getParameterValues和getParameterMap也可能须要覆盖

*/

@Override

public String getParameter(String name) {

String value = super.getParameter(xssEncode(name));

if (value != null) {

value = xssEncode(value);

}

return value;

}

/**

* 覆盖getHeader方法,将参数名和参数值都作xss过滤。

* 若是须要得到原始的值,则经过super.getHeaders(name)来获取

* getHeaderNames 也可能须要覆盖

*/

@Override

public String getHeader(String name) {

String value = super.getHeader(xssEncode(name));

if (value != null) {

value = xssEncode(value);

}

return value;

}

/**

* 将容易引发xss漏洞的半角字符直接替换成全角字符

*

* @param s

* @return

*/

private static String xssEncode(String s) {

if (s == null || s.isEmpty()) {

return 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;

case '%': // < 字符的 URL 编码形式表示的 ASCII 字符(十六进制格式) 是: %3c

processUrlEncoder(sb, s, i);

break;

default:

sb.append(c);

break;

}

}

return sb.toString();

}

public static void processUrlEncoder(StringBuilder sb, String s, int index){

if(s.length() >= index + 2){

if(s.charAt(index+1) == '3' && (s.charAt(index+2) == 'c' || s.charAt(index+2) == 'C')){ // %3c, %3C

sb.append('<');

return;

}

if(s.charAt(index+1) == '6' && s.charAt(index+2) == '0'){ // %3c (0x3c=60)

sb.append('<');

return;

}

if(s.charAt(index+1) == '3' && (s.charAt(index+2) == 'e' || s.charAt(index+2) == 'E')){ // %3e, %3E

sb.append('>');

return;

}

if(s.charAt(index+1) == '6' && s.charAt(index+2) == '2'){ // %3e (0x3e=62)

sb.append('>');

return;

}

}

sb.append(s.charAt(index));

}

/**

* 获取最原始的request

*

* @return

*/

public HttpServletRequest getOrgRequest() {

return orgRequest;

}

/**

* 获取最原始的request的静态方法

*

* @return

*/

public static HttpServletRequest getOrgRequest(HttpServletRequest req) {

if (req instanceof XssHttpServletRequestWrapper) {

return ((XssHttpServletRequestWrapper) req).getOrgRequest();

}

return req;

}

}

75d6c0430f8d4da99c4fa5d0.html

而后在web.xml中配置该filter:

75d6c0430f8d4da99c4fa5d0.html

xssFilter

com.xxxxxx.filter.XssFilter

xssFilter

/*

75d6c0430f8d4da99c4fa5d0.html

主要的思路就是将容易致使XSS攻击的边角字符替换成全角字符。< 和 > 是脚本执行和各类html标签须要的,好比

对于输入,处理使用XSS filter以外,对于每个输入,在客户端和服务器端还要进行各类验证,验证是否合法字符,长度是否合法,格式是否正确。在客户端和服务端都要进行验证,由于客户端的验证很容易被绕过。其实这种验证也分为了黑名单和白名单。黑名单的验证就是不能出现某些字符,白名单的验证就是只能出现某些字符。尽可能使用白名单。

3.2 对输出进行编码

在输出数据以前对潜在的威胁的字符进行编码、转义是防护XSS攻击十分有效的措施。若是使用好的话,理论上是能够防护住全部的XSS攻击的。

对全部要动态输出到页面的内容,统统进行相关的编码和转义。固然转义是按照其输出的上下文环境来决定如何转义的。

1> 做为body文本输出,做为html标签的属性输出:

好比:${username},

此时的转义规则以下:

< 转成 <

> 转成 >

& 转成 &

" 转成 "

' 转成 '

2> javascript事件

除了上面的那些转义以外,还要附加上下面的转义:

\ 转成 \\

/ 转成 \/

; 转成 ;(全角;)

3> URL属性

若是

确保:href 和 src 的值必须以 http://开头,白名单方式;不能有10进制和16进制编码字符。

4.HttpOnly 与 XSS防护

XSS 通常利用js脚步读取用户浏览器中的Cookie,而若是在服务器端对 Cookie 设置了HttpOnly 属性,那么js脚本就不能读取到cookie,可是浏览器仍是可以正常使用cookie。(下面的内容转自:http://www.oschina.net/question/12_72706)

通常的Cookie都是从document对象中得到的,如今浏览器在设置 Cookie的时候通常都接受一个叫作HttpOnly的参数,跟domain等其余参数同样,一旦这个HttpOnly被设置,你在浏览器的 document对象中就看不到Cookie了,而浏览器在浏览的时候不受任何影响,由于Cookie会被放在浏览器头中发送出去(包括ajax的时 候),应用程序也通常不会在js里操做这些敏感Cookie的,对于一些敏感的Cookie咱们采用HttpOnly,对于一些须要在应用程序中用js操做的cookie咱们就不予设置,这样就保障了Cookie信息的安全也保证了应用。

若是你正在使用的是兼容 Java EE 6.0 的容器,如 Tomcat 7,那么 Cookie 类已经有了 setHttpOnly 的方法来使用 HttpOnly 的 Cookie 属性了。

设置完后生成的 Cookie 就会在最后多了一个 ;HttpOnly

另外使用 Session 的话 jsessionid 这个 Cookie 可经过在 Context 中使用 useHttpOnly 配置来启用 HttpOnly,例如:

也能够在 web.xml 配置以下:

对于 不支持 HttpOnly 的低版本java ee,能够手动设置(好比在一个过滤器中):

String sessionid = request.getSession().getId();

response.setHeader("SET-COOKIE", "JSESSIONID=" + sessionid + "; HttpOnly");

对于 .NET 2.0 应用能够在 web.config 的 system.web/httpCookies 元素使用以下配置来启用 HttpOnly?

而程序的处理方式以下:

C#:

VB.NET:

.NET 1.1 只能手工处理:

PHP 从 5.2.0 版本开始就支持 HttpOnly

PS: 实际测试在 Tomcat 8.0.21 中在 web.xml 和 context中设置 HttpOnly 属性不起做用。只有cookie.setHttpOnly(true); 和

response.setHeader("SET-COOKIE", "JSESSIONID=" + sessionid+ "; HttpOnly"); 起做用。

参考连接:https://www.owasp.org/index.php/HttpOnly#Using_Java_to_Set_HttpOnly

5. 总结下

XSS攻击访问方法:对输入(和URL参数)进行过滤,对输出进行编码;白名单和黑名单结合;

--------------------------------------------分割线----------------------------------------------------

6.使用 OWASP AntiSamy Project 和 OWASP ESAPI for Java 来防护 XSS(还有客户端的esapi4js: esapi.js)

上面说到了防护XSS的一些原理和思想,对输入进行过滤,对输出进行编码。那么OWASP组织中项目 AntiSamy 和 ESAPI 就偏偏可以帮助咱们。其中 AntiSamy 提供了 XSS Filter 的实现,而 ESAPI 则提供了对输出进行编码的实现。(samy是一我的名,他第一次在MySpace上实现第一个XSS工具蠕虫,因此AntiSamy项目就是反XSS攻击的意思; ESAPI就是enterprise security api的意思;owasp: Open Web Application Securtiy Project)

使用maven能够引入依赖包:

75d6c0430f8d4da99c4fa5d0.html

org.owasp.antisamy

antisamy

1.5.3

org.owasp.esapi

esapi

2.1.0

75d6c0430f8d4da99c4fa5d0.html

使用AntiSamy构造XSS Filter的方法以下:

75d6c0430f8d4da99c4fa5d0.html 

XssFilter

75d6c0430f8d4da99c4fa5d0.html 

XssRequestWrapper

而后在web.xml中配置:

75d6c0430f8d4da99c4fa5d0.html 

web.xml

上面咱们不只对输入进行扫描过滤,并且设置了response中sessionId的httponly属性,咱们看下httponly的实际效果:

a51fca7e49054d1f9d745c382d91faa1-1.jpg

咱们看到baidu使用了httponly=true,咱们的localhost的httponly=true也其做用了。

ESAPI 编码输出,使用方法入下:

75d6c0430f8d4da99c4fa5d0.html

ESAPI.encoder().encodeForHTML(String input);

ESAPI.encoder().encodeForHTMLAttribute(String input);

ESAPI.encoder().encodeForJavaScript(String input);

ESAPI.encoder().encodeForCSS(String input);

ESAPI.encoder().encodeForURL(String input);

MySQLCodec codec = new MySQLCodec(Mode.STANDARD);

ESAPI.encoder().encodeForSQL(codec, String input);

75d6c0430f8d4da99c4fa5d0.html

对应上面 3.2 中说到的编码输出。encodeForSQL 用于 防护 MySQL 的 sql 注入。

(压缩版的esapi-compressed.js,大小为51K。)

-----------------------------------------------------

X-Frame-Options 响应头

X-Frame-Options HTTP 响应头是用来给浏览器指示容许一个页面能否在 , 或者 中展示的标记。网站可使用此功能,来确保本身网站的内容没有被嵌到别人的网站中去,也从而避免了点击劫持 (clickjacking) 的攻击。

使用 X-Frame-Options

X-Frame-Options 有三个值:

DENY

表示该页面不容许在 frame 中展现,即使是在相同域名的页面中嵌套也不容许。

SAMEORIGIN

表示该页面能够在相同域名页面的 frame 中展现。

ALLOW-FROM uri

表示该页面能够在指定来源的 frame 中展现。

换一句话说,若是设置为 DENY,不光在别人的网站 frame 嵌入时会没法加载,在同域名页面中一样会没法加载。另外一方面,若是设置为 SAMEORIGIN,那么页面就能够在同域名页面的 frame 中嵌套。

配置 Apache

配置 Apache 在全部页面上发送 X-Frame-Options 响应头,须要把下面这行添加到 ‘site’ 的配置中:

Header always append X-Frame-Options SAMEORIGIN

配置 nginx

配置 nginx 发送 X-Frame-Options 响应头,把下面这行添加到 ‘http’, ‘server’ 或者 ‘location’ 的配置中:

add_header X-Frame-Options SAMEORIGIN;

配置 IIS

配置 IIS 发送 X-Frame-Options 响应头,添加下面的配置到 Web.config 文件中:

...

...

结果

在 Firefox 尝试加载 frame 的内容时,若是 X-Frame-Options 响应头设置为禁止访问了,那么 Firefox 会用 about:blank 展示到 frame 中。也许从某种方面来说的话,展现为错误消息会更好一点。

Tomcat处理:

定义一个过滤器filter,在HTTP请求头中加入x-frame-options: SAMEORIGIN便可。

最后补充代码:

进行配置:

进行验证生效:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值