XSS更倾向于盗取用户信息,而CSRF更倾向于使用用户权限(用户不知情时),去达到自己的目的。
浏览器Cookie策略
当用户使用账号密码登陆之后,网站会给予用户两个cookie一个为Third-party cookie
,一个为Session cookie
,本地cookie存在于用户本机的一个文件上,这个文件通常对应一个域名,也就是说cookie可以跨一个域名下的多个网页,但是不能跨域名使用。在下次登陆时,可以直接作为登陆凭证,不必输入密码,服务器设置了Expired时间,当时间到了之后,才会失效。而Session cookie
存在与浏览器进程中,即使新打开的tab页面,Session cookie也是存在的,并且有效的。当浏览器关闭,则Seesion cookie
失效,session cookie主要是在记录登陆后的身份,使用户不会,每进入一个界面就重新登陆一次。
Cookie的各个参数
如果浏览器从一个域的页面中,要加载另一个域的资源,由于安全原因,某些浏览器会阻止Third-party Cookie的发送。导致无法进行csrf攻击。不过有的浏览器是允许发送第三方cookie的(比如firfox,chrome)
这是chrome的一些cookie,name,value分别对应了他们的值和id,domain和Path表明他们可以被那些域共享(我自己手动改了一下)。
domain
参数是用来控制 cookie对「哪个域」有效,默认为设置 cookie的那个域。这个值可以包含子域,也可以不包含它。如上图的例子,Domain选项中,可以是”.google.com”(不包含子域,表示它对google.com.hk的所有子域都有效),也可以是”www.google.com"(包含子域)。
path
用来控制cookie发送的指定域的「路径」,默认为”/“,表示指定域下的所有路径都能访问。它是在域名的基础下,指定可以访问的路径。例如cookie设置为”domain=.google.com; path=/123”,那么只有.google.com/123
及/123
下的任一子目录如/123/aaa
或/123/bbb
会发送cookie信息,而.google.com
就不会发送,即使它们来自同一个域。
secure
服务器端设置cookie的时候,可以指定secure
属性,这时cookie只有通过https协议传输的时候才会带到网络请求中,不加密的http请求不会带有secure cookie。
csrf攻击
在用户登陆之后,此时session cookie已经给予用户
1 | <img src=http://127.0.0.1/cg/index.php/tunan/delate?username=qq /> |
攻击者可以在自己的域内建立起一个网站,诱使目标用户点击这个链接,当点击这个链接时,用户会看到一张看不见的图片,而此时get请求已经发送,这个username为qq的用户已经被删除了。虽然我是另一个域名发起的请求,但是我是访问的正常网站,cookie就会被找到,然后被发送出去,所以达到了目的。
为什么成功了?
我们自己写一个cookie Demo一下。(php在5.2.0中加入了httponly,在第七个)
1 | setcookie(name,value,expire,path,domain,secure,httponly) |
在没加上这个html的图片链接时,因为是两个不同的域,所以cookie不会被发送,但是一旦发起此请求后,这是因为我请求的是这个cookie发出的域,浏览器会自动帮我们找到这个域给予我们的cookie,发送出去,也就导致了我们的登录信息被利用,从而形成csrf攻击。
P3P头
上面说过在一些浏览器是禁止本地cookie发送的(例如ie等),但是有时候我们发现在IE上也造成了csrf攻击,这其实是由于P3P头的问题。
什么是P3P头,其实这个是由w3c设置的一个关于隐私的标准,它可以设置浏览器的cookie的跨域问题,使得IE也不会拦截<script>
<iframe>
等标签可以在IE中不在拦截第三方cookie的发送。P3P头只需要网站设置一次,之后每次请求都会遵守此约定。所以仅仅依靠浏览器cookie策略完成对csrf的防御是不现实的。
GET POST
经过上面的发现,我们看到img等这种带有”src”属性的标签,只能发起一次GET请求,那么将接受的方式换为POST方式,是不是就可以杜绝这种攻击?
当然不是,攻击者可以在自己的域中制作一个form表单,然后使用js自动提交表单即可。当用户打开这个页面时,自动发起一次post请求,造成csrf攻击。
csrf-token
CSRF攻击是黑客利用了用户的凭证,因为攻击者可以完全伪造用户的请求,所以才导致了攻击的进行。请求中用户的凭证全部存储在cookie中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。所以要防御CSRF攻击,就必须在有一个凭证,在请求中有一个不能被伪造的数据段,而且不能和cookie有关。所以需要在请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。
1 | <input type=”hidden” name=”csrftoken” value=”tokenvalue”/> |
tokenvalue是完全随机的字符串,每次请求过来就校验他是否存在,是否正确,来判断这次请求是否合理。
这也是最常规的防御CSRF的方法。
Token
Session
是将要验证的信息存储在服务端,并以SessionId
和数据进行对应,SessionId
由客户端存储,在请求时将SessionId
也带过去,因此实现了状态的对应。而Token
是在服务端将用户信息经过编码过后传给在客户端,每次用户请求的时候都会带上这一段信息,因此服务端拿到此信息进行解密后就知道此用户是谁了。
http-Referer与csrf
http-Referer头,它记录了该 HTTP 请求的来源地址,即如果我们去访问一个目标网站,Referer头会记录我们是从哪一个网站转过来的。比如我们正在访问www.baidu.com,此时我们要访问www.a.com此时的Referer头会显示www.baidu.com。在ctf中也经常可以见到。
关于防护CSRF使用Referer的好处是,不需要任何的修改代码逻辑等等,只需要在请求加以限制,对相应的请求,校验他的Referer值,只要不是自己的域传来的请求,一律认为是非法的,不接受。就可以对CSRF加以防护,方便简单。
但是如果Referer被篡改呢?由于Referer并不是由服务器这边在管理,而是由浏览器来给出的,所以就相当于把安全交给了浏览器,而且校验Referer就相当于知道了访客是怎么来到当前页面的,可能造成用户的隐私泄露。同时用户是可以设置浏览器使其在发送请求时不再提供 Referer,那么就会导致合法用户无法完成操作。
cookie samesite
Cookie 的SameSite
属性用来限制第三方 Cookie,从而减少安全风险。
它可以分别设置3个值,分别是Strict,Lax.None
1 | Set-Cookie: CookieName=CookieValue; SameSite=Strict; |
Strict
Strict
最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。Lax
Lax
规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。即如果跨域使用GET请求是允许的,浏览器允许在发送GET请求时带上cookie凭证,而POST请求是不被允许的.
即在
www.baidu.com
上点击了一个表单(GET)链接,这个链接是指向www.a.com
的而假如a.com使用了Samesite-cookies并且将值设置为了Lax,那么用户是可以正常登陆到a.com的因为浏览器允许将cookie从A域发送到B域。而如果是POST链接就无法登陆。None
这种最宽松,与没有设置一样。
关于这一个属性,仅仅也只是对CSRF攻击进行了缓解而已,可以看到Strict过于严格,容易给用户带来很不好的体验,而Lax则不会防御GET形式的请求,而且需要用户浏览器支持 SameSite 属性。