开篇
身份认证,对于一个安全的应用来说,是第一道门槛,它为后续所有的安全措施提供了“身份”这样一个关键信息。
通常每个公司会有好几个外部应用,如果每一个应用使用独立的账号体系,管理起来会非常复杂,用户也需要保存好几个账号密码,严重影响使用体验。
而且公司内部的各个管理或开发系统,比如各种服务器、confluence、jira、gitlab等也都使用单独的账号,一个开发人员要记住各种纷繁杂乱的账号和密码,如果不提前保存下来,根本不可能能靠记忆完成输入。
这时,如何设计一个简单易用的身份认证体系就显得尤为重要。今天,我们就来聊聊身份认证所涉及的方方面面。
身份认证面临的威胁
大部分人理解的身份认证不过就是在登录页面输入用户名和密码,但在实际应用中,身份认证远不止用户名和密码。通常,根据认证场景的不同,我们可以将认证分为对外认证和对内认证。
对外认证,其实就是应用面向用户的登录模块,面向终端用户进行认证。一个应用通常只有一个登录入口,而且我们也可以在这个入口上实现各种认证方式,比如用户名密码、短信验证、甚至指纹识别等等。
对内认证,主要包括公司各内部系统的认证,这部分的场景就比较多了,比如开发服务器的登录认证,数据库登录的认证,内部管理后台的认证等等。
所以,对外认证是单一场景下的认证,对内认证是多场景下的认证。
目前大部分公司身份认证的现状是,对外认证相当重视,而忽视对内认证的重要性,这就导致各个公司的对内认证都比较薄弱。而且由于内部的认证场景过于分散,所以很难进行统一管理。尤其是服务器、数据库等的认证,很难做到统一,你总不能拿着一个账号密码就可以在内网通行无阻吧。因此,对内认证是一个需要长期治理的过程,需要我们投入较大的精力。
当然,不管是对外认证还是对内认证,它们面临的威胁都是相同的。身份认证面临的威胁主要包括无认证、弱密码、认证信息泄露。接下来,我们一个一个来看。
首先,没有认证环节是所有应用和公司存在的最普遍的问题。尤其是在对内认证的部分,我们经常会看到,很多公司的数据库、接口、管理后台在使用的时候,完全没有任何登录过程,直接“裸奔”在复杂的网络环境中。
其次,弱密码也是一个普遍存在的问题。人类的惰性是安全最大的敌人,设计一个好记的强密码并不是一件简单的事情,这也是弱密码屡禁不止的原因。
最后一个威胁是认证信息泄露。所谓认证信息泄露,就是指黑客通过各种手段,拿到了用户的密码信息和身份凭证这样的认证信息。常见的手段包括钓鱼、拖库等等。更可怕的是,很多攻击对于用户来说都是无感知的。
除了密码的直接泄露以外,大部分的登录系统都无法应对重放攻击。重放攻击简单来说就是,黑客在窃取到身份凭证(如 Cookie、Session ID)之后,可以通过发送http报文的形式在无密码的情况下完成认证。
一旦黑客仿冒了正常用户进行认证,那么就相当于获得了这个用户的所有权限。更严重的是,所有的后续操作,都会记录到这个正常用户的名下,使得后续应用进行授权和审计的时候,都很难发现黑客本身的存在。
保证身份认证的安全
事实上,很多时候,我们解决安全问题,不只是在解决一个技术问题,还要培养外部用户和内部员工的安全意识,通过一些规章制度去强化我们的对安全的重视程度。
下面我整理了一些基本的解决方案来保证身份认证的安全性,这其中有技术上的,也有规则制度上的。
接下来,我们回到开篇提到的身份信息过多而带来的身份管理问题。当账号体系变得越来越复杂时,如何对这些账号进行统一的管理,也是解决身份认证问题的关键。而单点登录(SSO single sign-on)就是一个非常有效的解决方案。
单点登录
单点登录的概念很简单:用户只需要进行一次认证,就可以访问所有的网页、应用和其他产品了。下面我介绍几种典型的单点登录方式,它们分别是:CAS 、JWT、OAuth 和 OpenID。
CAS
CAS,Central Authentication Service—中央认证服务,是耶鲁大学发起的一个企业级的、开源的项目,旨在为Web应用系统提供一种可靠的SSO解决方案。
注意,CAS 只是一个开源的单点登录理论框架,或者说只是一个协议,它不是某一种单点登录的具体实现,而是提供了一整套完整的落地方案。
下面,我们从CAS的几个基本概念入手,并给出一个CAS认证流程图来让大家加深理解。
首先,从物理结构上看,CAS协议包括两个组件: CAS Server 和 CAS Client 。
- CAS Server:负责认证用户并授予其对应用程序的访问权限, CAS Server需要独立部署 ;
- CAS Client:以软件包的形式与受保护的应用绑定在一起,负责处理对应用受保护资源的访问请求,需要对请求方进行身份认证时,重定向到 CAS Server 进行认证。
其次,CAS的核心就是Ticket(票据),及其在Ticket之上的一系列处理操作。CAS的主要票据为TGT、ST,我们一个一个来看。
TGT(Ticket Grangting Ticket)
TGT是CAS server为用户签发的登录票据,拥有了TGT,用户就可以证明自己在CAS成功登录过。用户在CAS server认证成功后,会生成一个TGT对象,该对象封装了Cookie值以及此Cookie值对应的用户信息,并放入CAS server的Session中。
同时,CAS server生成TGT对象中封装的Cookie,并发送到用户浏览器,如下:
// CAS server向用户浏览器设置的cookie值
Set-Cookie:CASTGC=TGT-2345678
TGT对象的ID就是Cookie中CASTGC保存的值,当用户再次请求认证时,如果用户浏览器传过来的有CAS server生成的Cookie,则CAS server以此cookie的值作为sessionID查询缓存中有无TGT对象,如果有的话,则说明用户之前登录过,如果没有,则用户需要重新登录。
ST(ServiceTicket)
ST是CAS server为用户签发的访问某一具体服务的票据。用户访问应用时,应用发现用户没有ST,则要求用户去CAS server获取ST。
用户向CAS server发出获取ST的请求,CAS server首先使用用户请求中携带的CASTGC Cookie项的值去查找是否存在TGT对象,如果存在TGT,则用此TGT签发一个ST,返回给用户。
用户凭借ST去访问应用,应用仍然需要拿ST去CAS server验证,验证通过后,才能允许用户访问资源。
为了保证ST的安全性:ST 是随机生成的,没有规律性。而且,CAS规定 ST 只能存活一定的时间,然后 CAS Server 会让它失效。而且,CAS 协议规定ST只能使用一次,无论 Service Ticket 验证是否成功, CAS Server 都会清除服务端缓存中的该 Ticket ,从而可以确保一个 Service Ticket 不被使用两次。
TGC (Ticket-granting cookie)
上面提到,CAS server生成TGT对象放入自己的Session中,而TGC就是这个Session的唯一标识(SessionID),也就是上面Set-Cookie中CASTGC项的值,以Cookie形式放到浏览器端,是CAS Server用来明确用户身份的凭证。
CAS认证完整流程
上面的讲述也许过于理论化,下面我画了一个完整的认证流程图,相信看完后你对CAS的认证流程能够理解的更清晰。
总结
CAS的官方文档在这个链接https://apereo.github.io/cas/4.2.x/index.html,同时,CSDN上有一篇讲CAS流程比较通俗的文章https://blog.csdn.net/qq_34246546/article/details/79493208。
CAS目前也维护了一个开源SSO项目,同时支持CAS、OAuth和Openid等等各种认证协议,链接是https://github.com/apereo/cas。
CAS 的流程非常经典,我们后面要讲的 3 种单点登录方式,都和 CAS 的流程相似,说它们是 CAS 的“衍生品”也不为过。所以说,理解 CAS 流程是理解其他三种认证方式的基础。
接下来的几篇文章,我们继续来讲述JWT、OAuth和OpenID的认证流程。