Cookie安全小结

Cookie机制:通常来讲,同域内浏览器中发出的任何一个请求都会带上Cookie,不管请求什么资源,请求时,Cookie出如今请求头的Cookie字段中。服务端响应头的Set-Cookie字段能够添加、修改和删除Cookie,客户端经过javascript也能够添加、修改和删除Cookie。另外,Cookie是没法跨浏览器存在的。javascript

利用Cookie机制,咱们能够存储用户的会话信息,好比,用户登认证后的Session,以后同域内发出的请求都会带上认证后的会话信息,很方便。也所以,攻击者特别喜欢盗取Cookie,这至关于盗取了目标网站上的用户权限。php

固然,有时对静态组件的Cookie读取是一种浪费,咱们能够用另外一个无Cookie的域名来存放这些静态组件。java

Cookie的重要字段以下:浏览器

[name] [value] [domain] [path] [expries] [max-age] [httponly] [secure]安全

其含义依次为:名称、值、所属域名、所属相对根路径、过时时间、是否有HttpOnly标志、是否有Secure标志。服务器

下面分别对domain、path 、httponly和secure字段进行说明:cookie

一、子域Cookie机制app

设置Cookie时,若是不指定domain的值,默认就是本域。dom

例如:a.foo.com域经过javascript设置一个Cookie,语句以下:测试

      document.cookie="test=1";

那么,domain值默认为a.foo.com。若是指定domain为父级域,好比:

      document.cookie="test=1;domain=foo.com";

此时,domain变为foo.com,这样带来一个好处就是能够在不一样的子域共享Cookie,坏处也很明显,就攻击者控制的其余子域也能读到这个Cookie。注意:这个机制不容许设置Cookie的domain为下一级子域或其余外域。

二、路径Cookie机制

设置Cookie时,若是不指定path的值,默认就是目标页面的路径。

例如:a.foo.com/admin/index.php页面经过javascript来设置一个Cookie,语句以下:

      document.cookie="test=1";

那么,path值默认为/admin/。经过指定path字段,javascript能够设置任意Cookie到任意路径下,可是只有目标路径下的页面javascript才能读取到该Cookie。

可是,经过设置path不能防止重要的Cookie被盗取。好比,/evil/路径想读取/admin/路径的Cookie。经过跨iframe进行DOM操做便可作到,/evil/路径下页面的代码以下:

 

xc=function(src){
    var o=document.createElement('iframe');//iframe进入同域的目标页面
    o.src=src;
    document.getElementsByTagName('body')[0].appendChild(o);
    o.onload=function(){//iframe加载完成后
        d=o.contentDocument||o.contentWindow.document;//获取document对象
        alert(d.cookie);//获取cookie
    };
}('http://a.foo.com/admin/index.php');

三、HttpOnly Cookie机制

HttpOnly是指仅在HTTP层面上传输的Cookie,当设置了HttpOnly标志后,客户端脚本就没法读写该Cookie,能有效地防护XSS攻击获取Cookie。以PHP setcookie为例,httponly.php文件代码以下:

<?php
setcookie("test",1,time()+3600,"","",0,0);    //设置普通cookie
setcookie("test_http",1,time()+3600,"","",0,1);//第7个参数(这里的最后一个)是HttpOnly标志,0为关闭,1为开启,默认为0
?>

请求这个文件后,设置了个两个Cookie,以下图所示:

 其中,test_http是HttpOnly Cookie。若是服务端响应的页面有Cookie调试信息,极可能会致使HttpOnly Cookie的泄漏。好比如下信息。

 Apache HTTP Server2.2.x多个版本没有严格限制HTTP请求头信息,HTTP请求头超过LimitRequestFieldSize长度时,服务器返回400(Bad Request)错误并在返回信息中将出错的请求头内容输出(包含请求头里的HttpOnly Cookie),攻击者能够利用这个缺陷获取HttpOnly Cookie。

大多数浏览器限制Cookies(每一个域50个Cookie)最大约为4kB,咱们设置为更大且为本地Cookie,让请求头长度超过Apache的LimitRequestFieldSize,从而引发400错误。这样受攻击者只能经过清除Cookie才能正常访问目标网站。

 

四、Secure Cookie机制

Secure Cookie机制指的是设置了Secure标志的Cookie仅在HTTPS层面上安全传输,若是请求是HTTP的就不会带上这个Cookie,这样能下降重要的Cookie被中间人截获的风险。

可是,Secure Cookie对于客户端脚原本说是可读写的,也就意味着,它可以被盗取和篡改。以下的javascript脚本代码可对已知的Secure Cookie进行篡改:

//path与domain必须一致,不然会被认为是不一样的Cookie
document.cookie="test_secure=1;path=/;secure;"

本地Cookie与内存Cookie

若是没设置过时时间,就是内存Cookie,这样的Cookie会随着浏览器的关闭而从内存中消失;若是设置了过时时间是将来的某个时间点,那么就是本地Cookie,这样的Cookie就会以文本形式保存在操做系统本地,待过时时间到了才会消失。如:

document.cookie="test_expires=1;expires=Mon,01 Jan 2112 00:00:00 GMT";//GMT时间,2112年1月1日才会过时

采用本地Cookie可让用户在将来某一段时间内都不须要进行登陆操做,提高用户体验,可是,若是攻击者经过XSS获得这样的本地Cookie后,就可以在将来很长一段时间内,甚至永久控制着目标用户的帐号权限。但这并不意味着内存Cookie更安全,由于攻击者能够给内存Cookie加一个过时时间,使其变为本地Cookie。

Cookie的P3P性质

HTTP响应头的P3P(Platform for Privacy Preferences Project)字段是W3C公布的一项隐私保护推荐标准。该字段用于标识是否容许目标网站的Cookie被另外一个域经过加载目标网站而设置或发送,但仅IE执行了该策略。

好比,evil域经过script或iframe等方式加载foo域。加载的时候,浏览器是否会容许foo域设置本身的Cookie,或是否容许发送请求到foo域时,带上foo域已有的Cookie。

下面是关于P3P策略在设置与发送的两个场景,P3P策略在这两个场景下是有差别的:

一、设置Cookie

在IE下,默认是不容许第三方域设置Cookie(本地和内存)的,除非foo域在响应的时候带上P3P字段,如:

P3P:CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"

该字段的内容自己意义不大,不须要记(固然咱们也没有时间去记这些没有特别意义的东西),只要知道这样设置后,被加载的目标域的Cookie就能够被正常设置了,设置后的Cookie在IE下会自动带上P3P属性(这个属性在Cookie中是看不到的),一次生效,即便以后没有P3P头,也有效。

二、发送Cookie

发送的Cookie若是是内存Cookie,则无所谓是否有P3P属性,就能够正常发送;若是是本地Cookie,则这个本地Cookie必须拥有P3P属性,不然,即便目标域响应了P3P头也没用。

咱们能够经过如下方法进行测试:

1)给host文件添加www.foo.com与www.evil.com域。

2)将以下代码保存为foo.php,并保证能经过www.foo.com/cookie/foo.php访问到。

<?php
//header('P3P:CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"');
setcookie("test0",'local',time()+3600*3650);
setcookie("test_mem0",'memory');
var_dump($_COOKIE);
?>

3)将以下代码保存为evil.php,并保证能经过www.evil.com/cookie/evil.php访问到。

<iframe src="http://www.foo.com/cookie/foo.php"></iframe>

4)IE浏览器访问www.evil.com/cookie/evil.php,因为没有响应P3P头,foo.php设置并未成功。

5)将foo.php的P3P响应功能的注释去掉,再访问www.evil.com/cookie/evil.php,能够发现本地Cookie(test0)与内存Cookie(test_mem0)都已设置成功。

6)修改foo.php里的Cookie名,好比,test0改成test1,test_mem0改成test_mem1等,注释P3P响应功能,而后直接访问www.foo.com/cookie/foo.php,这时会设置本地Cookie(test1)与内存Cookie(test_mem1),此时这两个Cookie都不带P3P属性。

7)再经过访问www.evil.com/cookie/evil.php,能够发现内存Cookie(test_mem1)正常发送,而本地Cookie(test1)没有发送。

8)继续修改foo.php里的Cookie名,test1改成test2,test_mem1改成test_mem2,去掉P3P响应功能的注释,而后直接访问www.foo.com/cookie/foo.php,此时本地Cookie(test2)与内存Cookie(test_mem2)都有了P3P属性。

9)这时访问www.evil.com/cookie/evil.php,能够发现test2与test_mem2都发送出去了。