Cookie、Session和Token
一、COOKIE:
在网站中,http请求是无状态的。也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。cookie的出现就是为了解决这个问题,第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个了。
Cookie的弊端:
- cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据。
- cookie 中的所有数据在客户端就可以被修改,数据非常容易被伪造
if (req.cookies.jack) { console.log(req.cookies.jack); res.send("welcome"); } else { res.cookie('jack', 'content', {maxAge: 60 * 1000}); res.send("no cookie"); }
Cookie的参数:
- path:表示 cookie 影响到的路径,匹配该路径才发送这个 cookie。
- expires 和 maxAge:告诉浏览器这个 cookie 什么时候过期,expires 是 UTC 格式时间,maxAge 是 cookie 多久后过期的相对时间。当不设置这两个选项时,会产生 session cookie,session cookie 是 transient 的,当用户关闭浏览器时,就被清除。一般用来保存 session 的 session_id。
- secure:当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效。
- httpOnly:浏览器不允许脚本操作 document.cookie 去更改 cookie。一般情况下都应该设置这个为 true,这样可以避免被 xss 攻击拿到 cookie。
二、SESSION:
为了解决cookie安全性问题,session应运而生。session和cookie的作用有点类似,都是为了存储用户相关的信息。不同的是,cookie是存储在本地浏览器,而session存储在服务器。存储在服务器的数据会更加的安全,不容易被窃取。session 的运作通过一个session_id来进行。当你浏览一个网页时,服务端随机产生一个 1024 比特长的字符串,然后存在你 (客户端)cookie 中的connect.sid字段中,下次再次请求的时候,会把该session_id携带上来,服务器根据session_id在session库中获取用户的session数据。就能知道该用户到底是谁,以及之前保存的一些状态信息。这种专业术语叫做server side session。
但存储在服务器也有一定的弊端,就是会占用服务器的资源,但现在服务器已经发展至今,一些session信息还是绰绰有余的。
app.use(session({ secret:'jack2016', // 建议使用 128 个字符的随机字符串,这里不写secret的话cookie存储的是不加密的sessionid name:'jacks', //cookie名字,这里cookie存的内容是用secret加密的sessionid, cookie: {maxAge:60*2000}, }));
session的可选参数:
- name: 设置 cookie 中,保存 session 的字段名称,默认为connect.sid。
- store: session 的存储方式,默认存放在内存中,也可以使用 redis,mongodb 等。express 生态中都有相应模块的支持。
- secret: 通过设置的 secret 字符串,来计算 hash 值并放在 cookie 中,使产生的 signedCookie 防篡改。
- cookie: 设置存放 session id 的 cookie 的相关选项,默认为(default: { path: '/', httpOnly: true, secure: false, maxAge: null })
- genid: 产生一个新的 session_id 时,所使用的函数, 默认使用uid2这个 npm 包。
- rolling: 每个请求都重新设置一个 cookie,默认为 false。
- resave: 即使 session 没有被修改,也保存 session 值,默认为 true。
三、加密的COOKIE
将session数据加密,然后存储在cookie中。这种专业术语叫做client side session。
比如,cookie 本应是{dotcom_user: 'alsotang'},如果我们签个名,比如把dotcom_user的值跟我的 secret_string 做个 sha1,cookie变成了
{ dotcom_user: 'alsotang', 'dotcom_user.sig': '4850a42e3bc0d39c978770392cbd8dc2923e3d1d', }
这样一来,用户就没法伪造信息了。一旦它更改了 cookie 中的信息,则服务器会发现 hash 校验的不一致。毕竟他不懂我们的 secret_string 是什么,而暴力破解哈希值的成本太高。
四、Token认证
通过sesson_id解决http无链接的问题,但web server不能设计为必须接受cookie 因为不能保证访问都是浏览器发起的。
解决办法:JWT(Json Web Token)。在HTTP header中包含token信息进行验证。
JWT的第一部分是一个js对象,表面JWT的加密方法。
{ "typ":"JWT", "alg":"HS256" }
JWT的第二部分是token的核心,包含了一些信息。
{ "business_id": [ "1" ], "store_id": [ "2", "4", "7", "996", "1021" ], }
第三个是JWT根据第一部分和第二部分的签名(Signature)