1.Cookie和Session兄弟
由于HTTP协议本身是无状态的,也就是说同一个用户前一次HTTP请求和后一次HTTP请求时相互独立的,无法判断后一次请求的用户是不是刚才的用户。为了记录用户的状态,才有了Cookie。Cookie实际上以key-value键值对的形式存储了一些文本信息数据,它将数据保存在客户端(浏览器)。
当浏览器(客户端)登陆网站请求服务器后,服务器的response中返回了Set-Cookie(与Cookie类似,也是键值对的一小段文本),浏览器(客户端)将这个Cookie保存起来,当下次该浏览器(客户端)再请求此服务器时,浏览器(客户端)把请求的网址连同该域的Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。
需要注意的是,由于同源策略的存在,不同源的网站不能使用对方网站的Cookie,也即是不可以跨域名的,隐私安全机制禁止网站非法获取其他网站的Cookie。所以,在CSRF中恶意网站其实并不能获取到信任网站的Cookie💢
Cookie和session是配套使用的。Cookie是将一些文本信息以键值对的形式保存在客户端,而Session是将某些信息保存在服务器端。因为HTTP协议是无状态,Cookie是在客户端实现状态保持,Session是在服务器端实现状态保持,通过两者的结合实现客户端和服务器连接的状态保持。那么如何才能将Cookie对应到正确的Session呢?利用sessionid。通常在数据库中有一个seesion表,存放着所有的Session数据,大家都知道数据库数据都有一个id,而sessionid就对应的这个id,所以通过浏览器传递过来的Cookie,服务器能找到对应id的Session实现连接的状态保持。
那么,为什么有了cookie还需要session呢?💥
用session只需要在客户端保存一个id,实际上大量数据都是保存在服务端。如果全部用cookie,数据量大的时候客户端是没有那么多空间的。
cookie只是实现session的其中一种方案。虽然是最常用的,但并不是唯一的方法。
全部在客户端保存,服务端无法验证,这样伪造和仿冒会更加容易。(伪造一个随机的id很难,但伪造另一个用户名是很容易的)
全部保存在客户端,那么一旦被劫持,全部信息都会泄露
客户端数据量变大,网络传输的数据量也会变大
2.更厉害的Token
token技术可以让服务器完全不用保存任何登录信息
token的流程是这样的。客户端登录通过后,服务器生成一堆客户端身份信息,包括用户名、用户组、有那些权限、过期时间等等。另外再对这些信息进行签名。之后把身份信息和签名作为一个整体传给客户端。这个整体就叫做token。之后,客户端负责保存该token,而服务器不再保存。客户端每次访问该网站都要带上这个token。服务器收到请求后,把它分割成身份信息和签名,然后验证签名,若验证成功,就直接使用身份信息(用户名、用户组、有哪些权限等等)
可以看出,相对于cookie/session机制,token机制中,服务器根本不需要保存用户的身份信息(用户名、用户组、权限等等)。这样就减轻了服务器的负担💟
我们举个例来说,假如目前有一千万个用户登录了,在访问不同的网页。如果用cookie/session,则服务器内存(或内存数据库)中要同时记录1千万个用户的信息。每次客户端访问一个页面,服务器都要从内存中查询出他的登录信息。而如果用token,则服务器内存中不记录用户登录信息。它只需要在收到请求后,直接使用客户端发过来的登录身份信息。
可以这么说,cookie/session是服务器说客户端是谁,客户端才是谁。而token是客户端说我(客户端)是谁,我就是谁。当然了,token是有签名机制的。要是客户端伪造身份,签名通不过。这个签名算法很简单,就是将客户端的身份信息加上一个只有服务器知道的盐值(不能泄露),然后进行md5散列算法(这里只是简化,方便理解,实际细节要稍复杂一些)
token因为服务器不保存用户身份信息,一切都依赖当初那个签名。所以存在被盗用的风险。也就是说一旦盗用,服务器可能毫无办法,因为它只认签名算法。而session机制,服务器看谁不爽,可以随时把他踢出(从内存中删掉)。正是因为如此,token高度依赖过期时间。过期时间不能太长。过期短,可以减少被盗用的风险😎
除了上面所说的,如果开发的系统足够小,倾向于使用cookie/session。如果系统同时登录用户多,集群服务器多,有单点登录需求,则倾向于使用token。
3.大恶魔CSRF
CSRF (Cross-site Request Forgery),中文名称:跨站伪造。危害是攻击者可以盗用你的身份,以你的名义发送恶意请求。比如可以盗取你的账号,以你的身份发送邮件,购买商品等。
客户端和淘宝断开连接后,但是客户端保存着淘宝给的cookie,这个记录着客户端的信息,用于确认客户端本人,但是钓鱼网站,给客户端发链接,让它点击了该链接进入一个页面,这个钓鱼页面里面可能写了如下代码:
<img src='http://www.taobao.com/action?k1=v1&k2=v2' width=0 height=0 />
这里width=0 height=0 表示图片是不可见的。这个语句会导致客户端浏览器器向另外的服务器(淘宝)发送一个请求。
因为浏览器不管该图片url实际是否指向一张图片,只要src字段中规定了url,就会按照地址触发这个请求。(浏览器默认都是没有禁止下载图片,这是因为禁用图片后大多数web程序的可用性就会打折扣)。加载图片根本不考虑所涉及的图像所在位置(可以跨域)。如果A网站不小心提供了get接口就非常不幸得中招了
意思是,客户端打开了钓鱼网站,却在不知情的情况下,发送了一个请求给淘宝,这个请求有可能是转账,付款等等,因为是客户端发出的请求,所以客户端会带上自己的cookie,这样就可以请求成功
4.Token预防CSRF
比如要进行转账的操作,服务器端会要求客户端传递token,如果是正常的转账操作,没问题
但是如果是点击钓鱼网站,然后触发向服务器端发出转账请求,这个请求是已经提前写好了放在钓鱼网站里面,它只能让客户端访问,取不到cookie,更取不到token,所以在请求中就明确要求写明放在cookie里面的token,就可以了
比如在银行里转账,银行页面上的转账请求链接,是银行服务器那边生成的链接,所以那边是可以在请求里面就加上你客户端的token的,但是钓鱼网站无法得到你的token,钓鱼网站仿造的转账请求链接是无法把token写入的,所以就无法生效
5.为什么要选择Token技术
token相对cookie的优势
无状态
基于token的验证是无状态的,这也许是它相对cookie来说最大的优点。后端服务不需要记录token。每个令牌都是独立的,包括检查其有效性所需的所有数据,并通过声明传达用户信息。
服务器唯一的工作就是在成功的登陆请求上签署token,并验证传入的token是否有效。
多站点使用
cookie绑定到单个域。foo.com域产生的cookie无法被bar.com域读取。使用token就没有这样的问题。这对于需要向多个服务获取授权的单页面应用程序尤其有用。
使用token,使得用从myapp.com获取的授权向myservice1.com和myservice2.com获取服务成为可能。
支持移动平台
好的API可以同时支持浏览器,iOS和Android等移动平台。然而,在移动平台上,cookie是不被支持的。
性能
一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算的Token验证和解析要费时得多。
6.更优秀的JWT技术
JWT 是能够安全传输信息的一种方式。通过使用公钥/私钥对 JWT 进行签名认证。此外,由于签名是使用 head 和 payload 计算的,因此你还可以验证内容是否遭到篡改。
JWT不用像普通token一样对比验证存于服务器端的用户信息,而是通过加密和解密计算,服务器端只需要保留secret私钥
说到底,token和session只是服务器端保存的数据量减少,但服务器端依旧是要保存客户端的相关信息的,那么如果网站新开一个服务器,还得把原先服务器的用户数据给拷贝一份,当然这是没用数据库的情况下,那么有什么办法可以不拷贝一份吗,这就要用到JWT了
token相对于是服务器端也要保留给每一个用户的那个签名,每次用户的客户端发送信息过来,服务器端分离出签名,与存在服务器上的签名进行对比来确认身份,但是JWT就是只要是能通过服务器私钥解密的就认为是合法的客户端,所以不用保存每个用户的签名信息