cookie,session,token,drf-jwt
1.cookie,session,token发展史
引入:我们都知道 http 协议本身是一种无状态的协议,一个普通的http请求简单分为三步:
客户端发送请求request
服务端收到请求并进行处理
服务端将结果respond给客户端
对于服务端来说
服务端如何知道当前请求的客户端是哪个用户
如何保证每次请求,服务器都知道是哪个用户
(1)cookie 就是存储在客户端的一段数据,采用的是在客户端保持 HTTP 状态信息。
HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据。它会在浏览器下次向同一服务器再发起请求时,被携带并发送到服务器上。通常 Cookie 用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态
cookie 的产生背景
随着互联网的发展,已经不仅仅是浏览网页了,越来越多的交互式网站兴起,如在线购物网站。这就 面临一个问题,每次访问请求,服务端需要知道当前请求客户端是谁。比如xxxx/a.php已经登陆了,跳转到xxxx/b.php 不能又登陆一次吧。
由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。
cookie 的运行机制:
A:客户端发送一个http请求到服务端;
B:服务端收到请求,进行处理;
C:服务端将结果response给客户端,http 头部包含Set-Cookie的通知;
D:客户端收到结果,发现Set-Cookie通知,将数据以key-value的形式保存在cookie中,以后每次request服务端都会带上cookie ,服务端通过cookie即可知道当前用户
cookie 的缺点:
i) cookie 保存在本地,数据非常容易被伪造,尤其是敏感数据,所以不安全;Cookie 常用来标记用户或授权会话,被浏览器发出之后可能被劫持,被用于非法行为,可能导致授权用户的会话受到攻击,因此存在安全问题。还有一种情况就是跨站请求伪造 CSRF,简单来说 比如你在登录银行网站的同时,登录了一个钓鱼网站,在钓鱼网站进行某些操作时可能会获取银行网站相关的Cookie信息,向银行网站发起转账等非法行为。
ii) cookie 过大或过多,都会导致http请求过慢,影响效率;
跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。跟跨网站脚本(XSS)相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。
跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。这利用了 Web 中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。不过这种情况有很多解决方法,特别对于银行这类金融性质的站点,用户的任何敏感操作都需要确认,并且敏感信息的 Cookie 只能拥有较短的生命周期。
同时 Cookie 有容量和数量的限制,每次都要发送很多信息带来额外的流量消耗、复杂的行为 Cookie 无法满足要求。
Cookie 主要用于以下三个方面:
- 会话状态管理(如用户登录状态、购物车等其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
(2)session 就是存储在服务器的数据, 采用的是在服务器保持HTTP状态信息。
session 的产生背景
为了解决cookie的安全型和效率问题,所以产生了session技术,session是依赖cookie技术实现的。当用户发送一个请求到服务器,服务器会先检查cookie中是否存在session_id(即发送一个随机字符串,每个用户的随机字符串不同), 如果不存在(说明是第一次请求),则会为该请求创建一个session对象,并将该session对象的session_id(放到响应头的set-cookie中),响应给客户端。
session 的缺点
i) session 保存在内存中,如果访问量很大,则服务器内存可能吃不消,影响服务器性能;
ii) 如果服务器做了负载均衡,则有可能获取不到session,影响服务器的扩展性:
每个用户只需要保存自己的(session id),可服务器要保存你们所有用户的session id,这可不是一个小数目。
所以,这对服务器来说变成了一个巨大的开销,严重的限制了服务器扩展能力。对于大型网站必然是集群化&分布式的服务器配置,小F通过机器A登录了系统,那session id 会保存在机器A上,那假设小F的下一次请求被转到机器B上怎么办?机器B上并没有存小F的session id。有时候会采用一点小伎俩: session sticky , 就是让小F的请求一直粘连在机器A上, 但是这也不管用, 要是机器A挂掉了, 还得转到机器B去。
那只好做session 的复制了, 把session id 在两个机器之间搬来搬去, 快累死了。后来有个叫Memcached的支了招: 把session id 集中存储到一个地方, 所有的机器都来访问这个地方的数据, 这样一来,就不用复制了, 但是增加了单点失败的可能性, 要是那个负责session 的机器挂了, 所有人都得重新登录一遍。
cookie和session的区别
session是存储服务器端,cookie是存储在客户端,所以session的安全性比cookie高
获取session里的信息是通过存放在会话cookie里的session id获取的。
而session是存放在服务器的内存中里,所以session里的数据不断增加会造成服务器的负担,所以会把很重要的信息存储在session中,而把一些次要东西存储在客户端的cookie里。
session的信息是通过session_id获取的,而session_id是存放在会话cookie中
当浏览器关闭的时候会话cookie消失,所以session_id也就消失了,但是session的信息还存在服务器端,只是查不到所谓的session,但它并不是不存在
(3)Token 是令牌的意思,由服务端生成并发放给客户端,是一种具有时效性的验证身份的手段。
Token 避免了 Session 机制带来的海量信息存储问题,也避免了 Cookie 机制的一些安全性问题,在现代移动互联网场景、跨域访问等场景有广泛的用途
简单的交互流程
- 客户端将用户的账号和密码提交给服务器;
- 服务器对其进行校验,通过则生成一个 token 值返回给客户端,作为后续的请求交互身份令牌;
- 客户端拿到服务端返回的 token 值后,可将其保存在本地,以后每次请求服务器时都携带该 token,提交给服务器进行身份校验;
- 服务器接收到请求后,解析关键信息,再根据相同的加密算法、密钥、用户参数生成 sign 与客户端的 sign 进行对比,一致则通过,否则拒绝服务;
- 验证通过之后,服务端就可以根据该 Token 中的 uid 获取对应的用户信息,进行业务请求的响应。
Token 方案的特点
- Token 可以跨站共享,实现单点登录;
- Token 机制无需太多存储空间。减轻服务端压力,Token 包含了用户的信息,只需在客户端存储状态信息即可,对于服务端的扩展性很好;
- Token 机制的安全性依赖于服务端加密算法和密钥的安全性;
以 JSON Web Token(JWT)为例,Token主要由三部分组成:
- Header 头部信息:记录了使用的加密算法信息;
- Payload 净荷信息:记录了用户信息和过期时间等;
- Signature 签名信息:根据 header 中的加密算法和 payload 中的用户信息以及密钥key来生成,是服务端验证服务端的重要依据。
三者区别:
cookie是存在客户端浏览器的键值对
session是存在于服务端的键值对
token是三段式,服务端生成的,存放在客户端(浏览器就放在cookie中,移动端:存在移动端中)
注意点:
secret是保存在服务器端的(加密方式+盐),jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,他就是你服务器的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret,那就意味着客户端是可以自我签发jwt了。
(4)drf-jwt
python第三方模块(djangorestframework-jwt)
(1)安装:pip3 install djangorestframework-jwt
(2)快速使用:
迁移表:因为它,默认使用auth的user表签发token;
创建超级用户:在auth的user表中要有记录;
不需要在写接口,如果是使用auth的user表作为用户表,它可以实现快速签发;
签发(登录):只需要在路由中配置(因为该第三方模块已经帮我们写好登录接口了)
JWT的构成
JWT就一段字符串,由三段信息构成的,将这三段信息文本用.
链接一起就构成了Jwt字符串,第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).
header
jwt的头部承载两部分信息:
-
声明类型,这里是jwt
-
声明加密的算法 通常直接使用 HMAC SHA256
payload
-
标准声明
-
公共声明
-
私有声明
标准声明 (建议但不强制使用) :
-
iss: jwt签发者
-
sub: jwt所面向的用户
-
aud: 接收jwt的一方
-
exp: jwt的过期时间,这个过期时间必须要大于签发时间
-
nbf: 定义在什么时间之前,该jwt都是不可用的.
-
iat: jwt的签发时间
-
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
以上是JWT 规定的7个官方字段,供选用
公共声明 : 公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端直接可以查看.
私有声明 : 私有声明是服务端和客户端所共同定义的声明,一般使用了ace算法进行对称加密和解密的,意味着该部分信息可以归类为明文信息。
signature
JWT的第三部分是一个签证信息,这个签证信息由三部分组成:
-
header (base64后的)
-
preload (base64后的)
-
secret 密钥
这个部分需要base64加密后的header和base64加密后的payload使用.
连接组成的字符串,然后通过header中声明的加密方式进行加盐secret
组合加密,然后就构成了jwt的第三部分。
注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
jwt的优点:
1. 实现分布式的单点登陆非常方便
2. 数据实际保存在客户端,所以我们可以分担服务端的存储压力
3. JWT不仅可用于认证,还可用于信息交换。善用JWT有助于减少服务器请求数据库的次数,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。
jwt的缺点:
1. 数据保存在了客户端,我们服务端只认jwt,不识别客户端。
2. jwt可以设置过期时间,但是因为数据保存在了客户端,所以对于过期时间不好调整。# secret_key轻易不要改,一改所有客户端都要重新登录
参考:
原文链接:https://blog.csdn.net/DiligentGG/article/details/127282886
原文链接:https://blog.csdn.net/qq_25096741/article/details/115124621