cookie、session、token
# 引入
首先想象一个系统,有一个登录的业务,你可以输入用户密码后完成登录。
但是HTTP是无状态的协议,每次发出一个请求,都不会带上相关的用户信息,这就意味着我们下次再访问同一个页面时,还需要再次进行登录操作。
怎么才能使得用户一次登录后,访问同一个网站可以不用再次进行登录呢?思路就是每次登录时带上用户的信息,在浏览器中就存在一个cookie对象,在指定的域下可以在http进行请求时带上cookie
# cookie
cookie一般存储在浏览器端,通常由服务器设置相关的cookie,并保存在浏览器端
第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个了。
特点:cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据。
给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。
# cookie什么时候产生呢?
Cookie的使用一先要看需求。因为浏览器可以禁用Cookie,同时服务端也可以不Set-Cookie。 客户端向服务器端发送一个请求的时,服务端向客户端发送一个Cookie然后浏览器将Cookie保存 Cookie有两种保存方式,一种是浏览器会将Cookie保存在内存中,还有一种是保存在客户端的硬盘中,之后每次HTTP请求浏览器都会将Cookie发送给服务器端。
# cookie生命周期
Cookie在生成时就会被指定一个Expire值,这就是Cookie的生存周期,在这个周期内Cookie有效,超出周期Cookie就会被清除。有些页面将Cookie的生存周期设置为“0”或负值,这样在关闭浏览器时,就马上清除Cookie,不会记录用户信息,更加安全。
# cookie缺点
①数量受到限制。一个浏览器能创建的 Cookie 数量最多为 300 个,并且每个不能超过 4KB,每个 Web 站点能设置的 Cookie 总数不能超过 20 个 ②安全性无法得到保障。通常跨站点脚本攻击往往利用网站漏洞在网站页面中植入脚本代码或网站页面引用第三方法脚本代码,均存在跨站点脚本攻击的可能,在受到跨站点脚本攻击时,脚本指令将会读取当前站点的所有Cookie 内容(已不存在 Cookie 作用域限制),然后通过某种方式将 Cookie 内容提交到指定的服务器(如:AJAX)。一旦 Cookie 落入攻击者手中,它将会重现其价值。 ③浏览器可以禁用Cookie,禁用Cookie后,也就无法享有Cookie带来的方便。
# session
用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。
- Session:在计算机中,尤其是在网络应用中,称为“
会话控制
”。Session 对象存储特定用户会话所需的属性及配置信息。
# session什么时候产生
当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。
这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。
服务器会向客户浏览器发送一个每个用户特有的会话编号sessionID,让他进入到cookie里
服务器同时也把sessionID和对应的用户信息、用户操作记录在服务器上,这些记录就是session。再次访问时会带入会发送cookie给服务器,其中就包含sessionID
服务器从cookie里找到sessionID,再根据sessionID找到以前记录的用户信息就可以知道他之前操控些、访问过哪里。
# session的生命周期
根据需求设定,一般来说,半小时。举个例子,你登录一个服务器,服务器返回给你一个sessionID,登录成功之后的半小时之内没有对该服务器进行任何HTTP请求,半小时后你进行一次HTTP请求,会提示你重新登录。 小结:Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。
# 优点
1⃣️存储在服务端:通过cookie存储一个session_id,然后具体的数据则是保存在session中。如果用户已经登录,则服务器会在cookie中保存一个session_id,下次再次请求的时候,会把该session_id携带上来,服务器根据session_id在session库中获取用户的session数据。就能知道该用户到底是谁,以及之前保存的一些状态信息。这种专业术语叫做server side session。 2⃣️将session数据加密,然后存储在cookie中。这种专业术语叫做client side session。flask采用的就是这种方式,但是也可以替换成其他形式。
缺点:
1⃣️当session越来越多时,会导致服务端的存储压力变大
2⃣️在分布式情况下,一个服务器中的session信息需要同步到平行的服务器节点中(当然也可以存储到中间件中,但是也会涉及到中间件节点挂掉的问题)
3⃣️session虽然是一个串,但是仍然有可能不篡改伪造,安全性不够高
# 那么如果浏览器禁用了cookie,session还可以使用吗?
还是可以使用的,因为session主要是存储于服务端的,如果客户端禁用了保存session的cookie,其实像http header或url都还是可以存储session的。
# token
基于签名机制。
注意token中没有用到公私钥,只是使用加密算法来判断是否数据没有被篡改
# 签名
签名主要是用来保证数据在传输过程中不会被恶意篡改
首先明确几个基本概念:
1、密钥对,在非对称加密技术中,有两种密钥,分为私钥和公钥,私钥是密钥对所有者持有,不可公布,公钥是密钥对持有者公布给他人的。
2、公钥,公钥用来给数据加密,用公钥加密的数据只能使用私钥解密。
3、私钥,如上,用来解密公钥加密的数据。
4、摘要,对需要传输的文本,做一个HASH计算,一般采用SHA1,SHA2来获得。
5、签名,使用私钥对需要传输的文本的摘要进行加密,得到的密文即被称为该次传输过程的签名。(看最下面的一部分就明白了)
6、签名验证,数据接收端,拿到传输文本,但是需要确认该文本是否就是发送发出的内容,中途是否曾经被篡改。因此拿自己持有的公钥对签名进行解密(密钥对中的一种密钥加密的数据必定能使用另一种密钥解密。),得到了文本的摘要,然后使用与发送方同样的HASH算法计算摘要值,再与解密得到的摘要做对比,发现二者完全一致,则说明文本没有被篡改过。
上面实际上介绍了加密解密和数字签名两个概念和实现过程,二者的过程正好是相反的。
# 结构
包含三个部分,之间用.
隔开
- Header
一般格式:
{
"alg":"HS256",
"typ":"JWT"
}
2
3
4
The header typically consists of two parts: the type of the token, which is JWT, and the signing algorithm being used, such as HMAC SHA256 or RSA.
该json会经过base64编码,形成如下的xxxxxx
- Payload
payload中一般会包括3个部分:
Registered claims (opens new window): These are a set of predefined claims which are not mandatory but recommended, to provide a set of useful, interoperable claims. Some of them are: iss (issuer), exp (expiration time), sub (subject), aud(audience), and others (opens new window).
Notice that the claim names are only three characters long as JWT is meant to be compact.
Public claims (opens new window): These can be defined at will by those using JWTs. But to avoid collisions they should be defined in the IANA JSON Web Token Registry (opens new window) or be defined as a URI that contains a collision resistant namespace.
Private claims (opens new window): These are the custom claims created to share information between parties that agree on using them and are neither registered or publicclaims.
An example payload could be:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
2
3
4
5
The payload is then Base64Url encoded to form the second part of the JSON Web Token.
Do note that for signed tokens this information, though protected against tampering, is readable by anyone. Do not put secret information in the payload or header elements of a JWT unless it is encrypted.
编码后形成下面的yyyyy
- Signature
主要包含的是签名的信息,在header中使用对应的算法对header和payload部分进行加密,最终形成签名。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
2
3
4
最终会将3个部分进行base64编码以便于各种协议进行数据的传输。
输出是三个由点分隔的Base64 URL字符串,可以在HTML和HTTP环境中轻松传递,同时与基于XML的标准(如SAML)相比更紧凑。
eg:xxxxx.yyyyy.zzzzz
更多信息可以查看官网:https://jwt.io/introduction
# 流程
1、首先,前端通过Web表单将自己的用户名和密码发送到后端的接口,这个过程一般是一个POST请求。建议的方式是通过SSL加密的传输(HTTPS),从而避免敏感信息被嗅探
2、后端核对用户名和密码成功后,将包含用户信息的数据作为JWT的Payload,将其与JWT Header分别进行Base64编码拼接后签名,形成一个JWT Token,形成的JWT Token就是一个如同lll.zzz.xxx的字符串 3、后端将JWT Token字符串作为登录成功的结果返回给前端。前端可以将返回的结果保存在浏览器中,退出登录时删除保存的JWT Token即可
4、前端在每次请求时将JWT Token放入HTTP请求头中的Authorization属性中(解决XSS和XSRF问题)
5、后端检查前端传过来的JWT Token,验证其有效性,比如检查签名是否正确、是否过期、token的接收方是否是自己等等
6、验证通过后,后端解析出JWT Token中包含的用户信息,进行其他逻辑操作(一般是根据用户信息得到权限等),返回结果
# 优点
这种基于token的认证方式相比传统的session认证方式更节约服务器资源,并且对移动端和分布式更加友好。其优点如下:
支持跨域访问:cookie是无法跨域的,而token由于没有用到cookie(前提是将token放到请求头中),所以跨域后不会存在信息丢失问题 无状态:token机制在服务端不需要存储session信息,因为token自身包含了所有登录用户的信息,所以可以减轻服务端压力 更适用CDN:可以通过内容分发网络请求服务端的所有资料 更适用于移动端:当客户端是非浏览器平台时,cookie是不被支持的,此时采用token认证方式会简单很多 无需考虑CSRF:由于不再依赖cookie,所以采用token认证方式不会发生CSRF,所以也就无需考虑CSRF的防御
而JWT就是上述流程当中token的一种具体实现方式,其全称是JSON Web Token,官网地址:https://jwt.io/