Cookie、Session、Token、JWT
前言:
- 最近重温接口测试,对cookie、session、token、jwt感到疑惑,在这里进行梳理,加深理解,也感谢csdn各位大佬的分享,东看看西搬搬,这里汇总下我了解到的内容
转载-原文链接:
https://blog.csdn.net/weixin_35681869/article/details/107096474
https://www.cnblogs.com/xiaolixun/p/8716232.html
https://zhuanlan.zhihu.com/p/100460817
https://blog.csdn.net/weixin_42170152/article/details/103738139
https://blog.csdn.net/AwayFuture/article/details/102753627
https://blog.csdn.net/qq_37939251/article/details/83511451
http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html --by 阮一峰
https://www.jianshu.com/p/bbba6b337c7e
几个概念
-
什么是认证(Authentication)
- 认证用户身份,证明“你是你”,互联网中的认证
- 人脸识别登录
- 账密登录
- 验证码登录
- 认证用户身份,证明“你是你”,互联网中的认证
-
什么是授权(Authorization)
- 用户授予第三方应用访问某些资源的权限
- 比如:登录app会弹出询问是否允许app获取相关权限(访问相册、地理位置)
- 实现授权的方式有:cookie、session、token、OAuth
- 用户授予第三方应用访问某些资源的权限
-
什么是凭证(Credentials)
- 实现认证授权的前提,一种证书,用于证明身份的媒介
- 可以认为是你的身份证
- 证明你学历的 毕业证和学位证
- 实现认证授权的前提,一种证书,用于证明身份的媒介
Cookie、Session产生的原因
- 早起互联网世界只有文字的获取,HTTP本身是无状态协议(对于事务处理没有记忆能力,每次客户端和服务端会话完成时,服务端不会保存任何会话信息):
- 每个请求都是完全独立的,服务端无法确认当前访问者的身份信息,无法分辨上一次的请求发送者和这一次的发送者是不是同一个人。
- 所以服务器与浏览器为了进行会话跟踪(知道是谁在访问我),就必须主动的去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一浏览器。而这个状态需要通过 cookie 或者 session 去实现。
Cookie
什么是Cookie
- cookie是保存在客户端的纯文本文件,如txt,也可以说是一门客户端缓存技术,用于保存客户端请求信息
Cookie的产生
1、cookie是由服务器产生,当浏览器第一次访问服务器,且服务器有Session方法,服务器此时并不知道他的身份,所以就会创建一个独特的身份标识数据,格式:key:value,以及服务端调用Session对象生成的JsessionId放入到set-Cookie字段里,随着响应报文发送给浏览器,
2、浏览器看到有set-Cookie 字段以后,就知道这是服务器给的身份标识,于是就保存起来,下次请求时自动将这个 key=value值放入到Cookie字段中发给服务端
3、服务端收到请求报文后,发现Cookie字段中有值,就能根据此值去寻找Session对象,识别该用户的身份,然后提供个性化的服务
Cookie重要属性
序号 | 属性 | 说明 |
---|---|---|
1 | name:value | 键值对,设置 Cookie 的名称及相对应的值,都必须是字符串类型 - 如果值为 Unicode 字符,需要为字符编码。- 如果值为二进制数据,则需要使用 BASE64 编码。 |
2 | domain | 指定 cookie 所属域名,默认是当前域名 |
3 | path | 指定 cookie 在哪个路径(路由)下生效,默认是 ‘/’。如果设置为/abc,则只有 /abc 下的路由可以访问到该 cookie,如:/abc/read。 |
4 | maxAge | cookie 失效的时间,单位秒。如果为整数,则该 cookie 在 maxAge 秒后失效。如果为负数,该 cookie 为临时 cookie ,关闭浏览器即失效,浏览器也不会以任何形式保存该 cookie 。如果为 0,表示删除该 cookie 。默认为 -1。- 比 expires 好用。 |
5 | expires | 过期时间,在设置的某个时间点后该 cookie 就会失效。一般浏览器的 cookie 都是默认储存的,当关闭浏览器结束这个会话的时候,这个 cookie 也就会被删除 |
6 | secure | 该 cookie 是否仅被使用安全协议传输。安全协议有 HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false。当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效。 |
7 | httpOnly | 如果给某个 cookie 设置了 httpOnly 属性,则无法通过 JS 脚本 读取到该 cookie 的信息,但还是能通过 Application 中手动修改 cookie,所以只是在一定程度上可以防止 XSS 攻击,不是绝对的安全 |
说明:XSS,跨站脚本攻击。攻击者获得页面的js权限,能操作页面的一切,包括Session Storage和未设置HTTP Only属性的Cookie
Cookie 特点汇总
cookie数据由服务器生成,发送给浏览器保存
cookie数据类型只能是字符串
cookie数据的格式:键值对
cookie数据过期机制:设置expire值
cookie是一门客户端技术,一般是由服务器生成返回给浏览器客户端来保存的,并且cookie是
以键值对的形式保存在浏览器客户端的,每一个cookie都会有name,value,domain,path,过期时间...。
cookie有很多使用场景,在项目中比较常见的有:
1.登录记住用户名
2.记录用户浏览记录
...
上面应用中大家最熟悉的应该就是记住用户名这个场景了,以京东网站的登录功能为例,当我
们登录了一次京东,后面再去登录页面登录的时候,会发现它会帮你回填之前的用户名,这个
场景就是通过cookie技术实现的。
拓展:cookie是有过期机制的,可以通过设置cookie的过期时间来控制cookie什么时候过期,
这个mp的过期时间为一个月,因此这一个月内只要不清除浏览器端的cookie数据,那么使用火
狐浏览器来访问京东的登录页面都可以看到手机号回填的效果。
Cookie的作用
- 存储会话信息,跟踪会话状态,联系浏览器和服务器
Cookie的优点
- 存储会话信息,可以用于跟踪会话状态
- 保存在浏览器,数据小,不会对服务器造成压力,提升了访问速度
- 可以长时间持续,也可以短时间持续(基于过期时间的设置)cookie可长可短,session一般较短
使用Cookie需要考虑的问题
-
客户端用户如果设置禁止 Cookie, 则 Cookie不能建立。
-
因为存储在客户端,容易被客户端篡改,使用前需要验证合法性
-
不要存储敏感数据,比如用户密码,账户余额,注意防止crsf攻击(cookie伪装)
说明:CSRF,跨站请求伪造,就是钓鱼网站,在网站A,发送一个向网站B的请求,由于浏览器会在请求中加上此域的Cookie, 所以如果在浏览器登录了网站B,又打开了钓鱼网站A,网站A构造的前往网站B的请求就会带上你的Cookie, 如果Cookie中有用户凭证,服务器认为你是登录用户,请求就会被响应。比如点赞、关注、发色情广告等请求)
-
使用 httpOnly 在一定程度上提高安全性
-
尽量减少 cookie 的体积,单个 Cookie 保存的数据不能超过 4K,
-
一个浏览器针对一个网站(其实就是一个domain)最多存 20 个Cookie,浏览器一般只允许存放 300 个Cookie
-
设置正确的 domain 和 path,减少数据传输
-
cookie会被附加在每个HTTP请求中,所以无形中增加了流量
-
cookie 无法跨域, 每个 cookie 都会绑定单一的域名,无法在别的域名下获取使用,一级域名和二级域名之间是允许共享使用的(靠的是 domain)
-
移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token
Session
什么是Session
- session是一门服务端会话缓存技术,用于存储一次会话的多次请求的数据
Session的产生
如下图,浏览器第一次请求,请求头中并未携带Cookie信息,上面我们也说,Cookie是由服务端生成,其实此时服务端调用HttpSession生成的Session对象(也可以认为session的产生更早于Cookie),它会产生一个JsessionId(名字可以自定义)随其他的key-value的信息一起写入到Set-Cookie,返回给浏览器,一般第一次请求和应答结束后JsessionId会自动失效,这是他的过期时间,一般它只存在于一次会话的开始和结束,我们往往也使用SessionId来跟踪记录会话时长
-
如下图1,浏览器第一次请求:
-
如下图2,浏览器第一次请求
-
如下图,浏览器第二次请求
对比jsessionid可看出,第一次请求后响应头的set-Cookie里的sessionid和 第二次请求是请求头里Cookie字段的sessionid是同一个,
- 交互流程
- 转载自 知乎(https://zhuanlan.zhihu.com/p/100460817)
Session特点汇总
session的特点:
session由服务器端的web容器创建,保存在服务器端。
session保存数据:键值对形式
session可以是任何数据类型,任意数据大小
session过期:默认30分钟
session持久化:用于解决重启服务器后session就消失的问题。在数据库中存储session,而不是存储在内存中。通过包:express-mysql-session
session是服务端的会话技术,当用户登录了系统,服务器端的web容器就会创建一个会话,此会话中可以保存登录用户的信息,并且也是以键值对的形式去保存的,现在大部分系统都是使用的session技术来做的鉴权(权限鉴定),即:当用户登录完了才可以访问系统中的一些页
面和数据。
其它:当客户端存储的cookie失效后,服务端的session不会立即销毁,会有一个延时,服务端会定期清理无效session,不会造成无效数据占用存储空间的问题。
以下面的系统为例:
直接访问系统lmcanon的首页index.html无法访问成功,会被重定向到登录页login.html,因为这个系统有做用户鉴权,没有登录的用户无法访问系统里面的数据。
Session的产生总结
(转载自https://www.cnblogs.com/xiaolixun/p/8716232.html ):
- session生成大概是,首先你发个请求去服务端,如果你的cookie里面有他之前写的session(叫什么都ok,jsessionid或者其他都行,取决于容器的实现),那么直接读取容器内存该sessionid对应的信息
- 如果是第一次请求,分2种情况:
- 如果服务端调用获取或设置session的方法,但是传过来的cookie里面没有(根本没cookie可传过去),那么自动生成一个session,并在响应头里面加上Set-Cookie,向浏览器申请写入cookie
- 如果服务端没有调用获取或设置session的方法,那么就不会生成并下发session,应该是为了节省网络以及服务器资源。
session相关概念
-
sessionStorage:客户端用于存储变量的,仅在当前会话下有效,关闭页面或浏览器后被清除
-
localStorage:除非被清除,否则永久保存
Session的作用
- 存储会话信息供浏览器后续请求使用,可以获取并修改变量的值。和cookie一起使用识别同一个客户。
Session的优点
- 相比JWT,最大优势是可以主动清除session。
- session保存在服务器端相对安全。
- 结合cookie使用,较为灵活,兼容性好
使用Session需要考虑的问题
-
将 session 存储在服务器里面,当用户同时在线量比较多时,这些 session 会占据较多的内存,需要在服务端定期的去清理过期的 session
-
查询session信息可能会有数据库查询操作,带来性能问题
-
当网站采用集群部署的时候,会遇到多台 web 服务器之间如何做 session 共享的问题。因为 session 是由单个服务器创建的,但是处理用户请求的服务器不一定是那个创建 session 的服务器,那么该服务器就无法拿到之前已经放入到 session 中的登录凭证之类的信息了。
-
当多个应用要共享 session 时,除了以上问题,还会遇到跨域问题,因为不同的应用可能部署的主机不一样,需要在各个应用做好 cookie 跨域的处理。
-
sessionId 是存储在 cookie 中的,假如浏览器禁止 cookie 或不支持 cookie 怎么办? 一般会把 sessionId 跟在 url 参数后面即重写 url,所以 session 不一定非得需要靠 cookie 实现
-
移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token
对比Cookie和Session
联系
- 都可以保存用户信息
- session的使用要求浏览器支持cookie,如果浏览器不支持or禁止cookie,则session不能使用
- 用户访问时,服务器创建or查找session,生成sessionid并传给浏览器,浏览器将其保存在cookie中一并放入内存,也可认为cookie是session在浏览器的标识
区别
- 安全性:Session 比 Cookie 安全,Session 是存储在服务器端的,Cookie 是存储在客户端的(客户端的容易被拦截,伪装)。
- 存取值的类型不同:Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session 可以存任意数据类型。
- 有效期不同:Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效。
- 存储大小不同: 单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie,但是当访问量过多,会占用过多的服务器资源。
5.保持状态的方案不同: cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。
Token
Token出现的背景
- 在早前的Web应用中,Web 基本上就是文档的浏览而已, 既然是浏览,作为服务器, 不需要记录谁在某一段时间里都浏览了什么文档,每次请求都是一个新的HTTP协议, 就是请求加响应, 尤其是我不用记住是谁刚刚发了HTTP请求,每个请求对我来说都是全新的;
2. 但是随着交互式Web应用的兴起,像在线购物网站,需要登录的网站等等,马上就面临一个问题,那就是要管理会话,必须记住哪些人登录系统, 哪些人往自己的购物车中放商品, 也就是说我必须把每个人区分开,这就是一个不小的挑战,因为HTTP请求是无状态的,所以想出的办法就是给大家发一个会话标识(session id), 说白了就是一个随机的字串,每个人收到的都不一样, 每次大家向我发起HTTP请求的时候,把这个字符串给一并捎过来, 这样我就能区分开谁是谁了;
3. 但是客户端只需要保存自身的session id,而服务器端则要保存所有客户端的session id ,这对服务器说是一个巨大的开销 , 严重的限制了服务器扩展能力;Token的出现解决了这个问题,因为服务端不需要存储Token的信息,而是通过CPU的计算 + 数据的加密解密再核对Token的方式来验证用户是否合法(即HTTP请求信息有没有被篡改),让服务器内存得到释放;
4. session id可以被伪造,没有采取加密的方法!!!,一旦攻击者通过session id伪造攻击,就会给服务器带来压力甚至击垮服务器。
5. Token是通过加密算法(如:HMAC-SHA256算法)来实现session对象验证的,这样使得攻击者无法伪造token来达到攻击或者其他对服务器不利的行为。
什么是Token(令牌)
token是服务端生成的一串字符串,以作客户端进行请求的令牌,访问资源接口(API)时所需要的资源凭证(身份证),当第一次登陆后,服务器生成一个token便将此token返回给客户端,以后客户端只要带上这个token前来请求数据即可,无需再次带上用户名和密码
Token的产生
- 原料:浏览器提供的登录信息:账密等用户信息
- 处理器:服务器
- 处理手段:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)登录信息做数字签名(哈希算法)
- 使用流程:
- 使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。流程是这样的:
- 客户端使用用户名跟密码请求登录
- 服务端收到请求,去验证用户名与密码 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端 客户端收到 Token
- 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
- 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token 服务端收到请求,然后去验证客户端请求里面带着的Token,如果验证成功,就向客户端返回请求的数据
- APP登录的时候发送加密的用户名和密码到服务器,服务器验证用户名和密码,如果成功,以某种方式比如随机生成32位的字符串作为token,存储到服务器中,并返回token到APP,以后APP请求时,
- 凡是需要验证的地方都要带上该token,然后服务器端验证token,成功返回所需要的结果,失败返回错误信息,让他重新登录。其中服务器上token设置一个有效期,每次APP请求的时候都验证token和有效期。
Token的特点
1、是由服务端校验客户端传输的账密成功后签发的一串字符串,发给了客户端,服务端可以缓存起来(因为token可以刷新)
2、保存在客户端的token自己保留有大量信息,服务器没有存储这些信息。
Token的作用
- 用来作身份验证
- 节省服务器内存
- 数据签名防伪造攻击
Token的优点
-
服务端无状态化、可扩展性好
- 在客户端存储的Tokens是无状态的,并且能够被扩展。基于这种无状态和不存储Session信息,负载负载均衡器能够将用户信息从一个服务传到其他服务器上。如果我们将已验证的用户的信息保存在Session中,则每次请求都需要用户向已验证的服务器发送验证信息(称为Session亲和性)。用户量大时,可能会造成 一些拥堵。但是不要着急。使用tokens之后这些问题都迎刃而解,因为tokens自己hold住了用户的验证信息。
-
支持移动端设备
- Tokens能够创建与其它程序共享权限的程序。当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理)
这时采用Token认证机制就会简单得多。
- Tokens能够创建与其它程序共享权限的程序。当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理)
-
安全
- 请求中发送token而不再是发送cookie能够防止CSRF(跨站请求伪造)。即使在客户端使用cookie存储token,cookie也仅仅是一个存储机制而不是用于认证。不将信息存储在Session中,让我们少了对session操作。token是有时效的,一段时间之后用户需要重新验证。我们也不一定需要等到token自动失效,token有撤回的操作,通过token revocataion可以使一个特定的token或是一组有相同认证的token无效。
-
支持跨域访问
- 我们提前先来谈论一下CORS(跨域资源共享),对应用程序和服务进行扩展的时候,需要介入各种各种的设备和应用程序。而Cookie是不允许垮域访问的(垮域访问:两个域名之间不能跨过域名来发送请求或者请求数据)
-
性能
- 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析要费时得多.
(内存型的session另说)
- 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析要费时得多.
-
解耦
- 不需要绑定到一个特定的身份验证方案。
Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可.
- 不需要绑定到一个特定的身份验证方案。
使用 token 时需要考虑的问题
-
如果你认为用数据库来存储 token 会导致查询时间太长,可以选择放在内存当中。比如 redis 很适合你对 token 查询的需求。
-
token 完全由应用管理,所以它可以避开同源策略
-
token 可以避免 CSRF 攻击(因为不需要 cookie 了)
-
移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token
refresh Token
简述
当用户登录的时候,生成access_token和refresh_token,并返回给APP。
当access_token失效时,APP使用refresh_token来请求刷新token。
如果refresh_token过期,需要用户重新登录,。也就是说,用户每一次登陆的时候refresh_token都会重新更改
Token 验证
refresh Token
对比session与token
作为身份认证,token安全行比session好;
Session 认证只是简单的把User 信息存储到Session 里,因为SID 的不可预测性,暂且认为是安全的。这是一种认证手段。 而Token ,如果指的是OAuth Token 或类似的机制的话,提供的是 认证 和 授权 ,认证是针对用户,授权是针对App 。其目的是让 某App有权利访问 某用户 的信息。
对比token与cookie
Cookie是不允许垮域访问的,但是token是支持的, 前提是传输的用户认证信息通过HTTP头传输;
token就是令牌,比如你授权(登录)一个程序时,他就是个依据,判断你是否已经授权该软件;cookie就是写在客户端的一个txt文件,里面包括你登录信息之类的,这样你下次在登录某个网站,就会自动调用cookie自动登录用户名;session和cookie差不多,只是session是写在服务器端的文件,也需要在客户端写入cookie文件,但是文件里是你的浏览器编号.Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端。
JWT
什么是JWT
JWT官网
json web token(阮一峰老师对JWT的介绍),(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,以JSON对象的方式在各方之间安全地传输信息,因为是基于数字签名所以可以进行验证和信任,常用的算法比如有HMAC、RSA等等。
JWT的产生
- json web token(阮一峰老师对JWT的介绍)
- 组成:
header、payload、签证 - 产生原理和流程
4. 在头部信息中声明加密算法和常量, 然后把header使用json转化为字符串
5. 在载荷中声明用户信息,同时还有一些其他的内容;再次使用json 把载荷部分进行转化,转化为字符串
6. 使用在header中声明的加密算法和每个项目随机生成的secret来进行加密, 把第一部分字符串和
第二部分的字符串进行加密, 生成新的字符串。词字符串是独一无二的。
7. 解密的时候,只要客户端带着JWT来发起请求,服务端就直接使用secret进行解密。
JWT的特点汇总
- 三部分组成,每一部分都进行字符串的转化
- 解密的时候没有使用数据库,仅仅使用的是secret进行解密。
- JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
- JWT验证客户端发来的token信息, 在服务端使用密钥校验就可以((校验也是 JWT 自己实现的)),不需要查询或者减少查询数据库,因为 JWT 自包含了用户信息和加密的数据。
使用 JWT 时需要考虑的问题
-
因为 JWT 并不依赖 Cookie 的,所以你可以使用任何域名提供你的 API 服务而不需要担心跨域资源共享问题(CORS)
-
JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
-
JWT 不加密的情况下,不能将秘密数据写入 JWT。
-
JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
-
JWT 最大的优势是服务器不再需要存储 Session,使得服务器认证鉴权业务可以方便扩展。但这也是 JWT 最大的缺点:由于服务器不需要存储 Session 状态,因此使用过程中无法废弃某个 Token 或者更改 Token 的权限。也就是说一旦 JWT 签发了,到期之前就会始终有效,除非服务器部署额外的逻辑。(处理方式参考:签名可以加时间戳或这其他随机参与加密,一旦登录就更新签名,之前的签名失效,不会出现多个在线啦)
-
JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
-
JWT 适合一次性的命令认证,颁发一个有效期极短的 JWT,即使暴露了危险也很小,由于每次操作都会生成新的 JWT,因此也没必要保存 JWT,真正实现无状态。
-
为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。
使用加密算法时需要考虑的问题
-
绝不要以明文存储密码
-
永远使用 哈希算法 来处理密码,绝不要使用 Base64 或其他编码方式来存储密码,这和以明文存储密码是一样的,使用哈希,而不要使用编码。编码以及加密,都是双向的过程,而密码是保密的,应该只被它的所有者知道, 这个过程必须是单向的。哈希正是用于做这个的,从来没有解哈希这种说法, 但是编码就存在解码,加密就存在解密。
-
绝不要使用弱哈希或已被破解的哈希算法,像 MD5 或 SHA1 ,只使用强密码哈希算法。
-
绝不要以明文形式显示或发送密码,即使是对密码的所有者也应该这样。如果你需要 “忘记密码” 的功能,可以随机生成一个新的 一次性的(这点很重要)密码,然后把这个密码发送给用户。
对比Token和JWT
- 相同
- 都是访问资源的令牌
- 都可以记录用户信息
- 都是使服务端无状态化
- 都是只有验证成功后,客户端才能访问服务端上受保护的资源
- 区别
- 服务端验证客户端发来的token信息要进行数据的查询操作;
- JWT验证客户端发来的token信息就不用, 在服务端使用密钥校验就可以(校验也是 JWT 自己实现的),不需要查询或者减少查询数据库,因为 JWT 自包含了用户信息和加密的数据。