文章目录
前言
身份认证在Web应用中,是保护我们服务资源非常重要的一个安全访问控制环节,从单体应用架构到分布式应用架构再到微服务架构,Web应用的安全访问在不断的经受考验。为了适应架构的变化、需求的变化,身份认证相关的方案、技术也需要不断的变革。
一、简单实用的认证技术-基于Session的认证
Web应用服务器与浏览器之间是基于HTTP协议进行通信的,而HTTP协议是无状态的,也就是说每一个请求之间都是相互独立的。但是随着应用业务需求复杂化,这时就需要通过保存用户状态,将用户的请求关联起来,然后提出了使用Session来解决这个问题的方案。Session在Web应用中隐含有“面向连接”和“保持状态”两个含义,有时候Session也用来指这种方案的存储。
在单体应用框架下基于 Session 的认证是最常用的一种认证机制。用户登录认证成功后,将用户相关数据存储到 Session 中,默认 Session 会存储在应用服务器中,并且将 SessionID 返回到客户端,存储在浏览器的 Cookie 中,用户下次访问服务器时请求中携带SessionID,Web应用程序通过此SessionID来验证用户是否登录。Session可以设置过期时间,默认是20分钟,并且过期时间随着请求不断的滑动,Session过期则会跳转到登录页面。
在单体应用架构中,由于所有的用户请求都是由这个唯一的服务器进行响应处理,所以只要把保存了用户信息和状态的Session对象,存放在应用服务器内存里,就能轻松地达到保持用户状态及身份认证的目的。有时为了Session存储的可靠性还可以放在数据库及独立的状态服务中。
二、架构变迁引发的Session问题
从单体应用架构到分布式应用架构再到微服务架构,基于Session的认证在不断的经受考验,首先要解决的问题就是在实施负载均衡后Session的访问及存储问题。Web应用程序集群或分布式部署之后,必须保证用户登录成功后无论下次请求落在哪个节点上,都能快速获取取到Session信息,显然使用单体应用中存储Session的方案是行不通的。
1.客户端Cookie方案
登录成功后将Session对象存储在Cookie中,每次客户端向服务器发送请求的时候,都会把整个Session对象放在请求里一起发送到服务器。这种方案实现起来虽然简单,但是由于Cookie的存储容量比较小,所以只适用于Session数据量小的场景,如果数据量比较大,会增加网络流量。还需要考虑安全性的问题,Cookie中不能存储敏感数据,或者cookie中的信息要加密存储。
2.Session复制方案
部分应用服务器能够支持Session复制功能,例如Tomcat,用户可以通过修改配置文件,让应用服务器进行Session复制,保持每一个服务节点的Session数据达到一致。但是这种方案的实现依赖于应用服务器,当应用被大量用户访问时,每个服务器都需要有一部分内存用来存放Session,同时因为大量Session通过网路传输进行复制,将会占用大量内存及网络资源,这种方案不太适合大型分布式应用。
3.Session共享方案
既然基于客户端Cookie及Session复制的方案都不完美,那么我们为什么不把Session放在一个统一的地方呢,这样集群中的所有节点都在一个地方进行Session的存取就可以解决问题。这种方案引入独立的外部存储,这就要求存储介质的读写速度要快、要保证数据不丢失。虽然可以把它存放在数据库中,但是大型分布式应用中更推荐使用性能更高的分布式KV数据库中,如 Redis,内存存储,读写速度快,支持数据持久化。
三、分布式服务架构下更适合的认证方案-基于Token的认证
移动互联网时代,更多的客户端类型有了要访问系统服务的需求,不同的客户端类型产生了不同的使用场景,这些场景有不同的环境安全威胁、不同的会话生命周期、不同级别的接口认证方式。随着Restful API、微服务的兴起, Token与API网关结合,在请求时,网关将用户令牌转换为微服务内部会话,这就意味着所有请求都通过网关,从而不仅为微服务提供了用户身份认证,还有效地隐藏了微服务,相比与基于Session的认证方案其更能满足不同客户端类型场景下的认证需求。
基于Token的认证流程如下图,用户输入登录信息(用户名和密码),发送到身份认证服务进行认证。份验证服务验证登录信息是否正确,返回接口(一般接口中会包含Token、权限范围、有效时间等信息),客户端存储Token,请求其他服务资源时携带Token,资源服验证Token信息是否有效,有效则执行后续业务程序,响应给客户请求的资源,无效则要求客户端重新获取Token。对于客令牌的编码方案,业界更多的使用 JSON Web Tokens(JWT),它足够简单且库支持程度也比较好。
基于Token的认证带来以下好处
1.防伪造
因为Token是有签名的,所以如果有人对头部以及载荷的内容解码之后进行修改,再进行编码的话,那么新的头部和载荷的签名和之前的签名就将是不一样的。而且,如果不知道服务器加密的时候用的密钥的话,得出来的签名也一定会是不一样的,被篡改的Token提交到服务器后,服务器对头部和载荷再次以同样方法签名之后发现,自己计算出来的签名和接受到的签名不一样,那么就说明这个Token的内容被别人动过的,服务器会拒绝这个Token。
2.防重放(防冒充)
服务端在生成Token时,使用客户端的UserAgent作为干扰码对数据加密,客户端进行请求时,会同时传入Token、 UserAgent ,服务端使用UserAgent对Token解密,从而验证用户的身份。如果只是把Token拷贝到另一个客户端使用,不同的UserAgent会导致在服务端解析Token失败,从而实现了一定程度的防冒充。但是攻击者如果猜到服务端使用UserAgent作为加密密钥,他可以修改自己的UserAgent 。
3.有效期
服务端在生成Token时,加入有效期。每次服务端接收到请求,解析Token之后,判断是否已过期,如果过期就拒绝服务,即使被冒充也只是在一定的时间段内有效,一定程度上减少损失。
总结
本文简要总结了从单体Web应用到分布式微服务架构的Web应用,被广泛使用的身份认证解决方案。总体来说在单体Web应用下,简单的基于Session的验证方案已能满足大部分需求。但在分布式服务架构下的身份认证面临着比较大的安全风险与挑战,基于Token的身份认证为分布式服务架构下的Web应用提供了更好的认证体系。