引用

https://segmentfault.com/a/1190000017831088
https://tech.meituan.com/2018/10/11/fe-security-csrf.html

cookie,session,token

cookie+session模式流程

  1. 首先,客户端会发送一个http请求到服务器端。
  2. 服务器端接受客户端请求后,建立一个session,并发送一个http响应到客户端,这个响应头,其中就包含Set-Cookie头部。该头部包含了sessionId。Set-Cookie格式如下
Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]
expires:到期时间如:2021-09-21T08:37:40.781Z
domain:域(从后往前读)如:.google.com (包含www.google.com)
path:路径可以接受 Cookie:/(所有)
  1. 在客户端发起的第二次请求,假如服务器给了set-Cookie,浏览器会自动在请求头中添加cookie
  2. 服务器接收请求,分解cookie,验证信息,核对成功后返回response给客户端

注意

  • cookie只是实现session的其中一种方案。虽然是最常用的,但并不是唯一的方法。禁用cookie后还有其他方法存储,比如放在url中
  • 现在大多都是Session + Cookie,但是只用session不用cookie,或是只用cookie,不用session在理论上都可以保持会话状态。可是实际中因为多种原因,一般不会单独使用
  • 用session只需要在客户端保存一个id,实际上大量数据都是保存在服务端。如果全部用cookie,数据量大的时候客户端是没有那么多空间的。
  • 如果只用cookie不用session,那么账户信息全部保存在客户端,一旦被劫持,全部信息都会泄露。并且客户端数据量变大,网络传输的数据量也会变大

面临的会话劫持和跨站脚本攻击(XSS)问题

在 Web 应用中,Cookie 常用来标记用户或授权会话。因此,如果 Web 应用的 Cookie 被窃取,可能导致授权用户的会话受到攻击。常用的窃取 Cookie 的方法有利用社会工程学(社工库)攻击和利用应用程序漏洞进行 XSS 攻击。

防御XSS

SessionId 可以通过url,隐藏域和cookie,其中cookie相对安全

  1. 设置HttpOnly。通过设置Cookie的HttpOnly为true,可以防止客户端脚本访问这个Cookie,从而有效的防止XSS攻击
  2. 加入Token校验。同样是用于检测请求的一致性,给攻击者制造一些麻烦,使攻击者即使获取了Session ID,也无法进行破坏,能够减少对系统造成的损失。但Token需要存放在客户端,如果攻击者有办法获取到Session ID,那么也同样可以获取到Token。

面临的CSRF(Cross-site request forgery跨站请求伪造)问题

跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。

假如一家银行用以运行转账操作的URL地址如下: https://bank.example.com/withdraw?account=AccoutName&amount=1000&for=PayeeName

那么,一个恶意攻击者可以在另一个网站上放置如下代码:

如果有账户名为Alice的用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会损失1000资金。

防御CSRF

  1. 令牌同步模式STP

当用户发送请求时,服务器端应用将令牌(英语:token,一个保密且唯一的值)嵌入HTML表格,并发送给客户端。客户端提交HTML表格时候,会将令牌发送到服务端,令牌的验证是由服务端实行的。令牌可以通过任何方式生成,只要确保随机性和唯一性(如:使用随机种子【英语:random seed】的哈希链 )。这样确保攻击者发送请求时候,由于没有该令牌而无法通过验证。

  1. 验证源Referer字段

HTTP头中有一个Referer字段,这个字段用以标明请求来源于哪个地址(通过origin字段亦可,但存在302重定向和同源策略的问题,有时候origion不存在)。在处理敏感数据请求时,通常来说,Referer字段应和请求的地址位于同一域名下。以上文银行操作为例,Referer字段地址通常应该是转账按钮所在的网页地址,应该也位于bank.example.com之下。而如果是CSRF攻击传来的请求,Referer字段会是包含恶意网址的地址,不会位于bank.example.com之下,这时候服务器就能识别出恶意的访问。

这种办法简单易行,工作量低,仅需要在关键访问处增加一步校验。但这种办法也有其局限性,因其完全依赖浏览器发送正确的Referer字段。虽然http协议对此字段的内容有明确的规定,但并无法保证来访的浏览器的具体实现,亦无法保证浏览器没有安全漏洞影响到此字段。并且也存在攻击者攻击某些浏览器,篡改其Referer字段的可能。

  1. 添加校验CSRF Token

由于CSRF的本质在于攻击者欺骗用户去访问自己设置的地址,所以如果要求在访问敏感数据请求时,要求用户浏览器提供不保存在cookie中,并且攻击者无法伪造的数据作为校验,那么攻击者就无法再运行CSRF攻击。这种数据通常是窗体中的一个数据项。服务器将其生成并附加在窗体中,其内容是一个伪随机数。当客户端通过窗体提交请求时,这个伪随机数也一并提交上去以供校验。正常的访问时,客户端浏览器能够正确得到并传回这个伪随机数,而通过CSRF传来的欺骗性攻击中,攻击者无从事先得知这个伪随机数的值,服务端就会因为校验token的值为空或者错误,拒绝这个可疑请求。

验证码和密码其实也可以起到CSRF Token的作用,而且更安全。

  1. 双重Cookie验证

在会话中存储CSRF Token比较繁琐,而且不能在通用的拦截上统一处理所有的接口。

那么另一种防御措施是使用双重提交Cookie。利用CSRF攻击不能获取到用户Cookie的特点,我们可以要求Ajax和表单请求携带一个Cookie中的值。

双重Cookie采用以下流程:

  • 在用户访问网站页面时,向请求域名注入一个Cookie,内容为随机字符串(例如csrfcookie=v8g9e4ksfhw)。
  • 在前端向后端发起请求时,取出Cookie,并添加到URL的参数中(接上例POST https://www.a.com/comment?csrfcookie=v8g9e4ksfhw)。
  • 后端接口验证Cookie中的字段与URL参数中的字段是否一致,不一致则拒绝。
    此方法相对于CSRF Token就简单了许多。可以直接通过前后端拦截的的方法自动化实现。后端校验也更加方便,只需进行请求中字段的对比,而不需要再进行查询和存储Token。

当然,此方法并没有大规模应用,其在大型网站上的安全性还是没有CSRF Token高,原因我们举例进行说明。

由于任何跨域都会导致前端无法获取Cookie中的字段(包括子域名之间),于是发生了如下情况:

Token

token 也称作令牌,由uid+time+sign[+固定参数],也就是上面STP提到的令牌
token 的认证方式类似于临时的证书签名, 并且是一种服务端无状态的认证方式, 非常适合于 REST API 的场景. 所谓无状态就是服务端并不会保存身份认证相关的数据

解释一下

token其实只是一种加密方式,他将密钥放在服务端,将加密后的数据交给客户端。但被加密数据来自哪里,服务端是否需要保存seesion其实只是使用方式,与token原理无关。

最安全的仍然是服务端保存token,服务端不保存的时候可以采用上网双重Cookie的模式,JWT(使用用户信息作为token一部分),但此时服务器也丧失了中止token的权利(除非格外添加逻辑),所以一般JWT设置过期时间,使用HTTPS