当前位置: 首页 > 后端技术 > Java

吃透Cookie、Session、Token、JWT

时间:2023-04-01 18:30:16 Java

什么是Authentication?通俗地说,就是验证当前用户的身份,证明“你是你自己”(例如:每天上下班签到,需要用指纹签到,当指纹匹配时在系统中注册的,登录成功)。互联网认证用户名和密码登录邮箱发送登录链接手机号接收验证码只要能收到邮箱/验证码,就默认你是账号的主人什么是授权?资源权限当你安装手机应用时,APP会询问是否允许权限(访问相册、地理位置等)当你访问微信小程序时,当你登录时,小程序会询问是否允许权限(获取昵称)、头像、地区、性别等个人信息)实现授权的方式包括:cookie、session、token、OAuth什么是Credentials?战国时期,商鞅改革法制,发明照体帖。身体照片帖子由政府发布。这是一块光滑、打磨精细的竹板,上面刻有持有者的头像和家乡信息。中国人肯定有,没有就被认为是黑户,间谍什么的。在现实生活中,每个人都会拥有一张专属的居民身份证,这是用来证明持有人身份的合法证件。通过身份证,我们可以办理手机卡/银行卡/个人贷款/交通卡等,是身份验证的凭证。在互联网应用中,一般网站(如掘金)有两种模式,访客模式和登录模式。在游客模式下,您可以正常浏览网站文章。一旦你想要点赞/收藏/分享文章,你需要登录或注册一个账号。当用户登录成功后,服务器会向用户使用的浏览器颁发一个令牌(token)。此令牌用于指示您的身份。浏览器每次发送请求,都会带上这个token,你就可以使用了。访客模式下不可用的功能。什么是CookieHTTP是一个无状态协议(没有事务处理的内存,每次客户端和服务器会话完成时服务器不会保存任何会话信息):每个请求都是完全独立的,服务器无法确认身份当前访问者的信息,无法判断上次请求的发送者与本次发送者是否为同一人。因此,为了进行会话跟踪(知道谁在访问我),服务器和浏览器必须主动维护一个状态,用于通知服务器前后两次请求是否来自同一个浏览器。而这个状态需要通过cookie或者session来实现。Cookie存储在客户端:Cookie是服务器发送给用户浏览器并存储在本地的一小段数据。下次浏览器再次向同一服务器发出请求时,它会被携带并发送给服务器。Cookies不跨域:每个cookies都绑定一个域名,不能在其他域名下使用。允许一级域名和二级域名共享使用(视域而定)。cookie的重要属性什么是SessionSession是另一种记录服务器和客户端会话状态的机制。Session是基于cookie实现的。session保存在server端,sessionId会保存在client端的cookie中。Session认证过程用户第一次请求使用服务器时,服务器根据用户提交的相关信息创建相应的Session。当请求返回时,将Session的唯一标识信息SessionID返回给浏览器。浏览器收到服务器返回的SessionID信息后,会将这些信息保存在Cookie中。同时cookie记录了SessionID属于哪个域名。当用户第二次访问服务器时,请求会自动判断该域名下是否有cookie信息。如果有,cookie信息会自动发送到服务器。获取SessionID,然后根据SessionID查找对应的Session信息。如果没有找到,说明用户没有登录或者登录无效。如果找到Session,则证明用户已经登录,可以进行下面的操作。根据以上流程,SessionID是连接Cookie和Session的桥梁,大部分系统也是根据这个原理来验证用户登录状态的。Cookie和Session安全性的区别:Session比Cookie安全,Session保存在服务器端,Cookie保存在客户端。访问值的类型不同:Cookie只支持存储字符串数据,如果要设置其他类型的数据,需要转成字符串,而Session可以存储任何数据类型。有效期不同:Cookies可以设置为长期有效。比如我们经常使用的默认登录功能,Session一般都有一个很短的过期时间,在客户端关闭(默认)或者Session超时的时候就会过期。存储大小不同:单个cookie保存的数据不能超过4K,session可以存储的数据比cookie多很多,但是当访问量过多时,会占用过多的服务器资源。什么是令牌(token)AccesssToken是访问资源接口(API)所需要的资源凭证。简单token的组成:uid(用户的唯一标识),time(当前时间的时间戳),sign(签名,token的前几位通过a压缩成一定长度的十六进制字符串哈希算法)。特点:服务器是无状态和可扩展的。支持移动设备安全。支持跨程序调用令牌认证过程:客户端使用用户名和密码请求登录,服务端收到请求验证用户名和密码。之后,服务器会颁发一个令牌,并将令牌发送给客户端。客户端收到token后,会存储起来,比如cookie或者localStorage。客户端每次向服务器请求资源时,都需要带上服务器根据服务器下发的token接收请求,然后对客户端请求中包含的token进行校验。如果验证成功,则将请求的数据返回给客户端。每个请求都需要携带一个token,token需要放在HTTP的Header中。基于令牌的用户认证是一种无状态的服务器端认证方式,服务器端不需要存储令牌数据。以解析token的计算时间换取session的存储空间,从而减轻服务器的压力,减少频繁的数据库查询。令牌完全由应用程序管理,因此可以避免同源策略。RefreshToken另一种令牌——刷新令牌refreshtoken是专门用于刷新访问令牌的令牌。如果没有refreshtoken,accesstoken也可以刷新,但是每次刷新用户都要输入登录用户名和密码,会很麻烦。有了refreshtoken就可以减少这个麻烦,客户端直接使用refreshtoken来更新accesstoken,不需要用户额外操作。AccessToken的有效期比较短。当AccesssToken过期失效时,可以通过RefreshToken获取新的Token。如果RefreshToken也失效,用户只能重新登录。RefreshToken及其过期时间保存在服务器的数据库中,只有在申请新的AccesssToken时才会进行验证,不会影响业务接口的响应时间,不需要像会话处理大量询问。Token和Session的区别Session是一种记录服务器和客户端会话状态的机制,使服务器有状态,记录会话信息。而Token是令牌,是访问资源接口(API)所需要的资源凭证。Token使服务器无状态,不存储session信息。Session和Token并不矛盾。作为身份认证令牌,安全性优于Session,因为每个请求都有签名,可以防止监听和重放攻击,而Session必须依赖链路层来保证通信安全。如果你需要实现有状态的会话,你仍然可以添加Session在服务器端保存一些状态。所谓Session认证只是简单地将User信息保存在Session中,由于SessionID的不可预测性,暂时认为是安全的。而Token,如果指的是OAuthToken或者类似的机制,提供认证和授权。认证是针对用户的,授权是针对应用的。其目的是赋予应用程序访问用户信息的权利。这里的Token是独一无二的。不能转让给其他应用,也不能转让给其他用户。Session只提供简单的认证,即只要有这个SessionID,就认为拥有这个User的所有权限。它需要严格保密。此数据应仅存储在网站上,不应与其他网站或第三方应用程序共享。所以简单来说:如果你的用户数据可能需要分享给第三方,或者允许第三方调用某个API接口,就使用Token。如果永远只是自己的网站和自己的App,用什么都无所谓。什么是JWTJSONWebToken(简称JWT)是目前最流行的跨域认证方案。它是一种身份验证和授权机制。JWT是一种基于JSON的开放标准(RFC7519),用于在Web应用程序环境之间传递声明。JWT声明一般用于在身份提供者和服务提供者之间传递经过认证的用户身份信息,从而从资源服务器获取资源。例如,它用于用户登录。JWT可以使用HMAC算法或RSA公钥/私钥进行签名。由于数字签名的存在,这些传输的信息是可信的。生成JWT的原理jwt.io/www.jsonwebtoken.io/JWTJWT认证流程:用户输入用户名/密码登录,服务端认证成功后,会返回一个JWT给客户端。客户端将token保存在本地(通常使用localstorage,也可以使用cookies)当用户想要访问受保护的路由或资源时,需要使用Bearer方式在请求头的Authorization字段中添加JWT,其内容如下下面的Authorization:Bearercopycode服务器端受保护的路由会在请求头Authorization中检查JWT信息,如果合法则允许用户的行为,因为JWT是自包含的(包含一些session里面的信息),从而减少了查询数据库的需要,因为JWT不使用cookie,所以你可以使用任何域名来提供你的API服务,而不用担心跨源资源共享(CORS),因为不再存储用户的状态在服务器的内存中,所以这是一种无状态的身份验证机制。JWT的使用方式客户端端接收服务端返回的JWT,可以保存在cookie中,也可以保存在localStorage中。方法1当用户想要访问受保护的路由或资源时,可以放在cookie中自动发送,但是这样不能跨域,所以最好放在HTTP请求头信息的Authorization字段中,使用Bearer模式添加JWT。GET/calendar/v1/eventsHost:api.example.comAuthorization:Bearer用户的状态不会保存在服务器的内存中,这是一种无状态的认证机制服务器的保护路由会检查请求头JWT信息在Authorization中,如果合法,则允许用户的行为。由于JWT是独立的,因此减少了查询数据库的需要。JWT的这些特性让我们可以完全依靠其无状态的特性来提供数据API服务,甚至可以创建下载流服务。因为JWT不使用cookie,所以你可以使用任何域名来提供你的API服务,而不用担心跨域资源共享(CORS)。方法二跨域时,可以将JWT放在POST请求的数据体中。方法三通过URL调用http://www.example.com/user?token=xxx项目JWT项目地址:https://github.com/yjdjiayou/jwt-demoToken与JWT一样用于访问资源Token可以记录用户信息,都使服务器无状态,只有验证成功后,客户端才能访问服务器上受保护的资源。DifferenceToken:服务端在验证客户端发送的Token时,还需要查询数据库获取用户信息,然后验证Token是否有效。JWT:Token和Payload加密保存在客户端。服务端只需要使用密钥解密验证即可(验证也是JWT自己实现的)。无需查询或缩减查询数据库,因为JWT自带用户信息和加密数据。常见的前后端认证方式Session-CookieToken验证(包括JWT、SSO)OAuth2.0(开放授权)常见的加密算法哈希算法(HashAlgorithm),又称散列算法、散列函数、散列函数,有一种从任何类型的数据中创建小型数字“指纹”的方法。散列算法重新打乱数据以重新创建散列值。哈希算法主要用于保证数据的真实性(即完整性),即发送方将原始消息和哈希值一起发送,接收方使用相同的哈希函数来验证原始数据是否真实。哈希算法通常具有以下特点:快如快:原始数据可以快速计算出哈希值逆向难度:基本不可能通过哈希值推导出原始数据输入敏感:只要原始数据稍有变化,得到的哈希哈希值相差很大避免碰撞:很难找到不同的原始数据得到相同的哈希值,宇宙中的原子数大约是10的60次方到80次方,所以有足够的2的256次方的空间容纳所有的可能性,当算法好的时候碰撞概率很低:2的128次方是340282366920938463463374607431768211456,也就是10的39次方2的160次方是1.4615016373382903686148,也就是48次方2级的256次方是1.1579208923731619542357098500869×10的77次方,也就是10的77次方。注:以上不能保证数据不会被恶意篡改。原始数据和哈希值都可能被恶意篡改,可以使用RSA公钥私钥方案,结合哈希值。哈希算法主要用于防止计算机传输过程中出现错误。早期的计算机使用前7位数据来确保第8位奇偶校验码(12.5%浪费效率低)。对于一段数据或文件,通过哈希算法生成128bit或256bit的哈希值,如果校验有问题,需要重传。常见问题使用cookies时需要考虑的问题因为它们存储在客户端,所以很容易被客户端篡改。使用前,您需要验证合法性。不要存储敏感数据,例如用户密码和帐户余额。使用httpOnly可以在一定程度上提高安全性,尽量减少cookies的体积,可以存储的数据量不能超过4kb。设置正确的域和路径以减少数据传输。Cookie不能跨域。一个浏览器最多可以为一个网站存储20个cookie。浏览器一般只允许移动终端存储300个cookies。支持不是很好,session需要基于cookie实现,所以常用的移动端是使用session需要考虑的token。会话存储在服务器中。当用户同时在线时,这些会话会占用更多的内存。,有必要定期清理服务器端的过期会话。当网站部署在集群中时,会遇到多个web服务器之间如何共享session的问题。因为session是由单个服务器创建的,但是处理用户请求的服务器不一定是创建session的服务器,那么服务器就无法获取到之前已经放在session中的登录凭证等信息。当多个应用要共享session时,除了上述问题外,还会遇到跨域问题,因为不同的应用可能部署在不同的主机上,需要在每个应用中处理cookie跨域处理。sessionId保存在cookie中,如果浏览器禁止cookies或者不支持cookies怎么办?一般是sessionId后面跟url参数重写url,所以session不一定需要依赖cookies。移动端对cookies的支持不是很好,session需要基于cookies实现,所以移动端常用token。需要考虑的问题如果你认为使用数据库存储token会导致查询时间过长,那么可以选择存储在内存中。比如redis就很适合你的token查询需求。令牌完全由应用程序管理,因此可以避免同源策略。令牌可以避免CSRF攻击(因为不需要cookie)。移动端对cookie的支持不是很好,session需要基于cookie实现,所以移动端常用token。使用JWT需要考虑的问题因为JWT不依赖cookie,所以你可以使用任何域名来提供你的API服务,而不用担心跨源资源共享(CORS)。JWT默认不加密,但也可以加密。原始Token生成后,可以用密钥再次加密。如果JWT未加密,则无法将机密数据写入JWT。JWT不仅可以用于身份验证,还可以用于交换信息。有效使用JWT可以减少服务器查询数据库的次数。JWT最大的优势就是服务端不再需要存储Session,可以方便的扩展服务端的鉴权认证业务。但这也是JWT最大的缺点:由于服务器端不需要保存Session状态,所以无法在使用过程中丢弃某个Token或者改变Token的权限。也就是说,JWT一旦发出,就会一直有效,直到过期,除非服务端部署了额外的逻辑。JWT本身包含认证信息,一旦泄露,任何人都可以获得token的所有权限。为了减少盗用,JWT的有效期应该设置的比较短。对于一些比较重要的权限,用户在使用时需要重新认证。JWT适用于一次性命令认证。签发一个有效期很短的JWT,即使暴露了,风险也很小。由于每次操作都会生成一个新的JWT,所以不需要保存JWT,真正做到了无状态。为了减少盗用,JWT不应使用HTTP协议以明文传输,而应使用HTTPS协议传输。使用加密算法时要考虑的事项切勿以明文形式存储密码始终对密码使用散列算法,切勿使用Base64或其他编码来存储密码,这与以明文形式存储密码相同,使用散列代替不要使用编码。编码和加密是双向过程,而密码是保密的,只应由其所有者知道。这个过程必须是单向的。哈希用于执行此操作。从来没有散列这种东西,而是编码中有解码,加密中有解密。切勿使用弱哈希或破解的哈希算法,如MD5或SHA1,仅使用强密码哈希算法。切勿以明文形式显示或发送密码,即使是向密码所有者也是如此。如果您需要“忘记密码”功能,您可以随机生成一个新的一次性(这很重要)密码,然后将这个密码发送给用户。分布式架构session下的session共享方案将session复制到任意一台服务器上并发生变化(增、删、改),节点会将session的所有内容序列化,然后广播给所有其他节点,而不管其他服务器是否是否需要会话。这确保了会话同步。优点:容错,服务器之间的会话可以实时响应。缺点:会对网络负载造成一定的压力。如果会话数量很大,可能会导致网络拥塞并降低服务器性能。stickysession/IP绑定策略是利用Ngnix中的ip_hash机制,将某个ip的所有请求都指向同一个服务器,也就是将用户绑定到服务器上。当用户第一次请求时,负载均衡器将用户的请求转发给A服务器。如果负载均衡器设置了stickysession,那么用户后续的每一次请求都会转发到A服务器,相当于连接了用户和A服务器。服务器粘在一起,这就是粘性会话机制。优点:简单,不需要对session做任何处理。缺点:缺乏容错能力,如果当前访问的服务器出现故障,将用户转移到第二台服务器上,他的session信息就会失效。适用场景:故障对客户影响不大;服务器故障是低概率事件。实现方法:以Nginx为例,在upstream模块配置ip_hash属性,实现粘性会话。会话共享(常用)采用分布式缓存方案,如Memcached、Redis来缓存会话,但需要将Memcached或Redis集群化,将会话存储在Redis中。虽然架构变得复杂,需要多访问一次Redis,但是这种方案带来的好处也是很大的:实现了session共享;可以横向扩展(增加Redis服务器);服务器重启时session不会丢失(还要注意Redis中session的刷新/失效机制);不仅是跨服务器的Session共享,甚至是跨平台(如网页、APP)的session持久化,将session存储在数据库中,保证session的持久化。优点:如果服务器出现问题,会话不会丢失。将session存储在数据库中会给数据库带来很大的压力,需要额外的开销来维护数据库。只要关闭浏览器,session就真的消失了吗?错误的。对于session,除非程序通知服务器删除一个session,否则服务器会永远保留它。程序一般会在用户注销时发送删除会话的命令。但是浏览器在关闭前从来不会主动通知服务器自己将要关闭,所以服务器永远没有机会知道浏览器已经关闭。造成这种错觉的原因是大部分session机制使用sessioncookies来保存sessionids,关闭浏览器后sessionid消失,再次连接服务器时就找不到原来的session了。如果服务器设置的cookie保存在硬盘上,或者通过某种手段改写浏览器发送的HTTP请求头,将原来的sessionid发送给服务器,打开浏览器仍然可以打开原来的session再次。正是因为关闭浏览器不会导致session被删除,才迫使服务器为session设置一个过期时间。当客户端最后一次使用会话的时间超过这个过期时间时,服务器认为客户端已经停止了它的活动。该会话将被删除以节省存储空间。作者:秋天的树叶不落juejin.cn/post/6844904034181070861