Csrf Token防止csrf攻击的原理?

最近学习Csrf攻击的防御手段,百度了许多CSRF攻击、Cookie、和csrfToken的相关文章。

CSRF攻击的过程:

图示

image.png

分析

1.用户C通过浏览器登陆并浏览信任网站A;
2.在用户C的浏览器中生成网站A的Cookie;
3.用户C通过浏览器访问恶意网站B;
4.在恶意网站B的一些HTML标签(一张图片)或者js中有一些代码,让用户C去访问网站A(发送用户C对网站A的request),进行一些恶意操作;例如:

 银行网站A,它以GET请求来完成银行转账的操作,如:
 http://www.mybank.com/Transfer.php?toBankId=11&money=1000危险网站B,
 它里面有一段HTML的代码如下:
 <img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>

5.此时,这个request请求会携带网站A的Cookie去请求网站A;
网站A无法识别请求是否是用户的请求,还是恶意网站盗用身份后的请求,所以会按照请求内容进行操作。

使用csrfToken的整个流程:

在一个客户端登录时服务端生成加密的token令牌,返回给客户端存储(可存储在cookie中),此后每次请求服务端都携带该cookie,且在http请求头或请求体中以参数的形式携带token,然后由服务端来解密cookie中的token,将其与请求报文中的token对比是否一致,以此来验证是来自合法用户的请求。

参考:
https://www.jianshu.com/p/674...
https://blog.csdn.net/sdb5858...
https://www.cnblogs.com/wnval...
https://www.cnblogs.com/sabli...
https://blog.csdn.net/besmart...
https://blog.csdn.net/besmart...

之前我一直有个疑问:

既然冒用者可以冒用合法用户的cookie,用户的COOKIE就像是一张门禁卡一样,攻击者可以盗用用户的门禁卡,以被盗用户的身份来执行一些设计增删改的操作,既然用户已经盗用了用户的COOKIE刷卡进门了,这个COOKIE对攻击者的防御也应该也就失效了才对呀。

那么csrfToken还有什么作用呢?

我的思考

经过又一波百度,以及个人思考我得到了一个可能的答案:
【个人理解】:

  • 所谓的CSRF跨站请求伪造,与其说是“冒用”或“伪造”,不如说是一个“钓鱼陷阱”。因为前两个称呼夸大了CSRF的灵活性,实际上,它只是一段被恶意用户预设的,死的代码段,它是不具备主观能动性的,更像是一个陷阱,通过诱导不知真相的用户来触发,然后执行固定的脚本。
  • 就像上述那个csrf攻击的实例,进入B网站,触发加载那张图片的确实是“我”(用户),那么浏览器就会去“我”的本地文件中去找到cookie,像网站A发送请求。这个过程与我直接访问网站A是一样的。因此才会有“冒用”一说。
  • 或者说,这一种说法是站在恶意用户的角度定义的,对于恶意用户,是冒用“我”的身份达到攻击的目的,而站在“我”的角度,是恶意用户通过“陷阱”达到攻击目的。
    ////////////////////////////////////分隔符//////////////////////////////////

    了解到这个角度,我再看CSRF Token校验流程,就能明白了:
  • 根据上述csrf Token校验流程,说到客户端浏览器会在请求网站A的服务端的时候,在Cookie中带一个token,还会在请求头/体或者请求参数中带一个token,然后由服务端对比二者是否一致。这是正常的校验流程。那么第一个关键点就来了:在非正常的,csrf攻击过程中,陷阱那段脚本(请求)是不变的,且是预设的,因此无法预知是哪个用户踩中了陷阱,就无法在这个请求体中加上该用户的taken!因此必不可能通过网站A后端的校验比对。

    看到这里可能还存疑:
  • 虽然无法预设这个“陷阱”触发的请求的token,但可以在脚本中即时获取踩中这个陷阱的当前用户的cookie中的token呀?比如我们自己开发时就能够通过getCookie获取到其中内容...
    那么,第二个关键点来了:浏览器的CORS同源策略!!现在我点击触发了这个“陷阱”,浏览器引擎执行B网站当前页面的这个“陷阱”脚本时,假设其中有getCookie()类似代码,想要拿到的资源(就是我本地存储cookie的那个文件),但这时候它是在B网站触发的,由于当前页面的域名ip与我的主机ip不一致导致跨域了,因此浏览器会阻止B网站共享到该资源(我本地的cookie文件)。

最后,还有一个问题:

  • 上面说的同源策略阻止跨域资源共享,在浏览器执行getCookie后,是
    确实拿到了cookie但检测到跨域因而没有返回给B网站,还是先检测,跨域了就不去取cookie呢?
  • 这一点与ajax请求跨域被浏览器同源策略拦截是一致的吗?

以上全部个人理解,不保证完全正确。

我的希望:

希望我的答案能够得到确认

如果哪错了,还望指正。


已经查证:我上述的“csrfToken 校验流程”,实际上叫做《双重Cookie验证》,
本质上是客户端发了两个token给服务端,一个在请求中,一个在cookie中,需要服务端解密后比对二者,检查是否合法和是否被篡改。
详细过程如下
  • 在用户登录后,由客户端生成一个令牌token(加密,且伪随机),将其放入cookie中
  • 在请求时,携带Cookie一起发送,并将token作为参数拼接在url后
  • 后端校验发送过来的Cookie中的token和url后的参数是否相等
  • 要求每个请求都将此token作为隐藏表单值
此外,另一种类似的防止CSRF的方法是《令牌同步模式》,
本质上还是在服务端存了token,然后拿它和客户端发来的请求中带的token比对
详细过程如下
  • 由服务端生成一个伪随机、且加密的token(令牌),可以针对每个用户会话或针对每个请求生成一次,然后发送给客户端
  • 当客户端发出请求时,携带该令牌用以服务器端校验,只有和服务端存储在session中的令牌一致,才正常响应,否则拒绝这次请求。
  • CSRF令牌不应使用Cookie进行传输(防范xss攻击),而是--

    • 在隐藏字段form参数中添加令牌,或者
    • 在自定义HTTP请求标头中插入CSRF令牌
再者,Cookie的httpOnly属性,阻止客户端读取cookie,仅允许cookie被用在请求中,它是通过kill掉浏览器的document.cookie 属性,只有在http请求头中会带有此cookie的信息,以此阻止xss攻击窃取cookie的。
然后,Cookie的sameSite属性,阻止跨站请求携带cookie,它是通过指定一个Cookie 是否能被跨站发送来限制第三方Cookie的,说白了就是阻止B网站触发csrf脚本请求A网站接口时,不让该请求携带Cookie。
最后,Cookie的domain属性,是阻止跨站读取cookie的作用。

最最后,我也找到了回答“浏览器何时拦截跨域”的问题:

在数据返回的时候采取判断是否是同源,而不是在请求的时候进行判断是不是同源
原因:如果服务端在响应头中设置了可以跨域权限,则浏览器则不会拦截响应数据

阅读 12.5k
3 个回答
在一个客户端登录时服务端生成加密的token令牌,返回给客户端存储(可存储在cookie中),此后每次请求服务端都携带该cookie,且在http请求头或请求体中以参数的形式携带token,然后由服务端来解密cookie中的token,将其与请求报文中的token对比是否一致,以此来验证是来自合法用户的请求。

这个 token 通常是放在表单里的,也可以放 JS 里,实际上放哪都可以就是不能放在 cookie 里,谁敢放 cookie ,立马以故意制造漏洞危害网站安全的理由开除,一点都不冤枉。

你贴的第一个参考链接里面就用加粗字体强调了:

由此可知,抵御CSRF攻击的关键在于:在请求中放入攻击者所不能伪造的信息,并且该信总不存在于cookie之中。

原则上是不能放在 cookie 中的,因为其 csrf 的本质就是 cookie 被利用,所以你放在普通的 cookie 中的话,那就和不加没有区别了。

但是,可以设置 cookie 的 SameSite 参数来限定跨站点的 cookie 发送。

参考:

浏览器端获取 cookie 是从 document.cookie 来解析的,而 cookie 存在一个 domain 属性,这个属性规定了 cookie 将会被存放到哪个域下,其他域是读取不到的,当然子域可以。

另外 cookie 还有 httpOnly 属性,这个属性可以限定浏览器不能从 document.cookie 中获取 cookie ,从而也就避免了被读取的可能。

另外,需要说明的是 cookie 中的域概念和 cors 中的跨域是不一样的。

新手上路,请多包涵

我觉得这是两种防范策略:

  1. csrftoken,请求时除了携带cookie以外,还需要在请求url或请求体中携带token,服务端校验cookie和token,服务端需要存储token,或者利用某种算法计算得到token
  2. 双重cookie验证,这种服务端不需要存储token,而是将token加入到cookie中( csrf一般由第三方网站发起,因此攻击者只能使用cookie而拿不到cookie的值,但是也存在同站的情况,该情况这种方式就无效),客户端拿到cookie和token以后,每次请求除了携带token还需要在header或请求体携带token,服务端拦截请求后先解密出cookie中的token与header或请求体token比对,一致才放行。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进