写作提纲
1. http协议的无连接、无状态特性
2. 单点登录、登出的交互是如何进行的:client,application A,application B,认证中心
3. 全局会话与局部会话
4. 单点登录的实现:联系代码
5. 单点登录的企业级实现:框架是如何来实现的
6. 单点登录的安全性
7. 单点登录中的其他问题:比如令牌如何生成
一、http协议的无连接无状态特性
现在大多数web应用采用的是browser/server架构,http作为通信协议。http是无连接、无状态的协议,这两个特性都后来web应用的架构和设计点产生了很大的影响。
无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
无状态是指协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。即我们给服务器发送 HTTP 请求之后,服务器根据请求,会给我们发送数据过来。再次访问发送HTTP请求之后,服务器会把我们当成从未服务过的新人一样,只会根据我们的请求来响应,和上次以及后来的HTTP请求没有任何的关联。
图1 http请求的无连接无状态特性
HTTP 协议这种特性有优点也有缺点,优点在于解放了服务器,每一次请求"点到为止"不会造成不必要连接占用,缺点在于每次请求会传输大量重复的内容信息。
客户端与服务器进行动态交互的 Web 应用程序出现之后,HTTP 无状态的特性严重阻碍了这些应用程序的实现,毕竟交互是需要承前启后的,简单的购物车程序也要知道用户到底在之前选择了什么商品。
再比如,在一个需要登录的系统(目前大多数企业级应用都有登录功能),我第一次登录的时候需要输入账号密码。如果没有其他任何机制的话,对于这个系统我们只能登录,其他的什么都干不了,想一下为什么。
于是,两种用于保持 HTTP 连接状态的技术就应运而生了,一个是 cookie,而另一个则是 session。
二、Web应用的会话机制:cookie和session
cookie和session都可以用来解决http协议无状态的特性,简单回顾一下它们的区别。
cookie是由网景公司的前雇员Lou Montulli在1993年发明的,现今cookie已经广泛使用了。
cookie 和session 的区别回顾:
1. cookie数据存放在客户的浏览器上,session数据放在服务器上。
2. cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。
3. session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能。
4. 浏览器对每个站点的cookie数,以及每个cookie的大小都是有限制的。
服了这些人了,为啥转载不附上原作的地址!!!
Cookie的属性和跨域问题中有如下描述
个域名下面可能存在着很多个cookie对象,cookie具有多个属性:
name字段为一个cookie的名称
value字段为一个cookie的值
domain字段为可以访问此cookie的域名,Servlet中通过setDomain()设置
非顶级域名,如二级域名或者三级域名,设置的cookie的domain只能为顶级域名或者二级域名或者三级域名本身,不能设置其他二级域名的cookie,否则cookie无法生成。
顶级域名只能设置domain为顶级域名,不能设置为二级域名或者三级域名,否则cookie无法生成。
二级域名能读取设置了domain为顶级域名或者自身的cookie,不能读取其他二级域名domain的cookie。所以要想cookie在多个二级域名中共享,需要设置domain为顶级域名,这样就可以在所有二级域名里面或者到这个cookie的值了。
顶级域名只能获取到domain设置为顶级域名的cookie,其他domain设置为二级域名的无法获取。
然后又发现了一个淘宝、天猫跨域请求实现分析的技术文章:Cookie跨域问题
其实大致原理如此,通过在www.taobao.com 的server端提供一个获取当前域下所有cookie的 php的请求地址,然后该php获取到cookie之后将期并成 js 代码,也就是以上第二个截图所看到的。然后再在 tmall 采用 jsonp 的方式跨域加载该 js 代码,从而实现 cookie 的跨域访问。
三、单系统登录
单系统的会话机制是如何实现的呢?
上面说到过cookie是存储客户端的(浏览器),而session是保存在服务器端的。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上它还有其他选择。
保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于SEEESIONID。
但cookie可以被人为的禁止,则必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面。还有一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。
四、多系统登录
上面讲到了,单系统登录中关键的部分是要通过cookie来传递会话标识来维护会话状态。但是cookie是有限制的,域名、大小。既然这样,为什么不将web应用群中所有子系统的域名统一在一个顶级域名下,例如“*.baidu.com”,然后将它们的cookie域设置为“baidu.com”,这种做法理论上是可以的,甚至早期很多多系统登录就采用这种同域名共享cookie的方式。然而,可行并不代表好,共享cookie的方式存在众多局限。首先,应用群域名得统一;其次,应用群各系统使用的技术(至少是web服务器)要相同,不然cookie的key值(tomcat为JSESSIONID)不同,无法维持会话,共享cookie的方式是无法实现跨语言技术平台登录的,比如java、php、.net系统之间;第三,cookie本身不安全。因此,我们需要一种全新的登录方式来实现多系统应用群的登录,这就是单点登录。
五、单点登录
单点登录(Single Sign On)解决的问题是登录一个系统之后就可以在多个系统之间可以免登陆访问。
单点登录不仅仅是登录还有注销。
为了在多个系统之间能够登录,单点登录需要一个独立的认证中心。
在博客单点登录原理与简单实现中有一个图讲的很清楚
这里分两个部分来描述单点登录的过程
第一部分是第一次登陆,第一次登录我们肯定是要输入账号、密码进行登录的,上图中也描绘的很清楚
- 用户访问系统1的受保护资源,系统1发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数
sso认证中心发现用户未登录,将用户引导至登录页面 - 用户输入用户名密码提交登录申请
- sso认证中心校验用户信息,创建用户与sso认证中心之间的会话,称为全局会话,同时创建授权令牌
- sso认证中心带着令牌跳转会最初的请求地址(系统1)
- 系统1拿到令牌,去sso认证中心校验令牌是否有效
- sso认证中心校验令牌,返回有效,注册系统1
- 系统1使用该令牌创建与用户的会话,称为局部会话,返回受保护资源
第二部分是已登录的账号免登陆到另一个系统。
- 用户访问系统2的受保护资源
- 系统2发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数
- sso认证中心发现用户已登录,跳转回系统2的地址,并附上令牌
- 系统2拿到令牌,去sso认证中心校验令牌是否有效
- sso认证中心校验令牌,返回有效,注册系统2
- 系统2使用该令牌创建与用户的局部会话,返回受保护资源
cnblogs上还有个专门做单点登录的,我也是服气,单点登录SSO:图示和讲解
6.1 用户未登录时访问子站一,子站一服务器检测到用户没登录(没有本站session,因为没传过来session对应cookie),于是通知浏览器跳转到SSO服务站点,并在跳转的URL参数中带上当前页面地址,以便登录后自动跳转回本页。
6.2 SSO服务站点检测到用户没有登录,于是显示登录界面。
用户提交登录请求到服务端,服务端验证通过,创建和账号对应的用户登录凭据(token)。
然后,服务端通知浏览器把该token作为SSO服务站点的cookie存储起来,并跳转回子站一,跳回子站一的URL参数中会带上这个token。
6.3 浏览器在写SSO服务站点cookie后,跳转回子站一。
子站一服务端检测到浏览器请求的URL中带了单点登录的token,于是把这个token发到SSO服务站点验证。
SSO服务端站点拿token解密出用户账号,把账号信息中允许子站一访问的部分返回给子站一。
子站一根据返回的信息生成用户在本站的会话,把会话对应cookie写入浏览器,从而完成在本站的登入以及会话保持。之后用户访问再子站一时,都会带上这个cookie,从而保持在本站的登录状态。
6.4 用户再访问子站二。子站二服务器检测到用户没登录,于是通知浏览器跳转到SSO服务站点。
6.5 浏览器访问SSO服务站点时会带上上述6.2环节创建的token这个cookie。SSO服务站点根据该token能找到对应用户,于是通知浏览器跳转回子站二,并在跳转回去的URL参数中带上这个token。
6.6 子站二服务端检测到浏览器请求的URL中带上了单点登录的token,于是又会走上述6.3对应步骤,完成用户在本站的自动登录。
这里有个问题是在登录系统2的时候是要进行验证的,这个时候没有账号信息,拿头做验证?
在本文讲cookie的时候提到过一篇文章讲taobao与tmall做跨域的cookie的方法可以用,假如cookie被禁用了咋办,我还是想实现单点登录怎么办呢?不跨域的cookie使用只能在同一个二级域名下了。
京东的跨域sso
js遍历sso,通过jQuery.ajax()方法对其中的每条数据发起跨域的jsonp请求;
可以看到返回一个重定向的Response,而且是跨域的重定向,由于发起的是跨域的jsonp请求,所以浏览器会根据返回的重定向url发起一次请求,也就是最后的跨域设置Cookie的请求
SSO实施和业务系统开发不同,它是技术点密集但工作量少的业务。如果你的开发人员还要为“如何跨域传token”、“如何读写AD”之类现学摸索,那实施结果往往存在较大安全漏洞,也会导致工期不可预测。这一块的很多现成产品都有特定的实施要求和局限性(本人曾填坑Oracle的OIM 和 ESSO),加之实施人员对产品熟悉程度不一,导致企业稍有自身特定的情况,就会要花费大量工时研究调整,甚至最终无法按需交付。
我的实现中,认证系统和应用系统是通过url参数来传递ticket,可能存在一些不稳定因素。应用系统的每次请求都会通过HTTP远程到认证系统进行验证ticket,速度上应该会慢一些,这里可以改进一步,在每个应用系统中也维护一份tickets,验证时,首先到本系统中验证,如果不存在,再远程到认证系统进行验证,但这也增加了应用系统的代码量。
在登录的过程中起始出现了两种级别的会话
六、单点登录代码示例和部署
如果用SOA来做单点登录的话还挺简单的
七、单点登录的企业级实现:框架是如何来实现的
spring + shiro + cas 实现sso单点登录
sso-shiro-cas
spring下使用shiro+cas配置单点登录,多个系统之间的访问,每次只需要登录一次,项目源码
系统模块说明
cas: 单点登录模块,这里直接拿的是cas的项目改了点样式而已
doc: 文档目录,里面有数据库生成语句,采用的是MySQL5.0,数据库名为db_test
spring-node-1: 应用1
spring-node-2: 应用2
其中node1跟node2都是采用spring + springMVC + mybatis 框架,使用maven做项目管理
最近做项目遇到了多个系统权限用的是shiro框架,需要做成单点登录,虽然shiro为单点登录提供了shiro-cas的方案,但是不太符合我们现有项目的框架,现在和大家分享一下我是如何实现单点登录。整体思路是参考cas。
框架图:
流程介绍
- 用户第一次访问系统A
- 系统A的ssoFilter发现当前session没有用户信息就重定向到登录服务器http://loginservice/login?redirecturl=url
- 登录服务器判断当前用户是否登录如果该用户登录则重定向到用户访问http://redirecturl?sessionid=sessionidg否则调到登录页面
- 系统A的ssoFilter发现当前session没有用户信息但是有参数sessionid,说明该请求是从单点登录服务器跳转过来的并且该用户是已经登录。在ssoFilter中为response添加addcookie(sessionid),且为response写入输出流,该输出流为一个html页面其中有一段js代码是访问系统A中用户访问的url
- 浏览器执行步骤4中返回js,此时访问系统A时携带的cookie中的sessionid是在单点登录系统登录的sessionid,A系统ssoFilter发现该用户已登录允许访问本系统资源。
也就是说在单点登录实现的时候还是要依靠链接重定向与cookie。
如果不用cookie该怎么办呢?
此前使用过cas做单点登录,做了一半发现这个不可行,因为应用场景的限制不能基于cookie来识别用户通过验证与否。
在sof上面也提过问,就是说让在url里面加入token,不过不太理解。
请问大家是否有做过相关的东西,如果有的话,能帮我解惑吗?
其实 Cookie 在用户登录里的作用也只是存一个 Session ID 而已,你可以自己实现一套 Session 机制把 Session ID 通过 URL 来传递。
在很久很久以前那些手机版网站(那时候手机普遍不支持 Cookie)就是这么做的。
其实与其在网站上面做这么恶心的 workaround,不如在客户机上面处理。比如说用具备回话隔离功能的浏览器(比如说 Google Chrome 登录不同的 Google 账户后相互之间的 Cookie 就是不互通的)。
上面说过cookie是不能跨域的,通过特殊设置setDomain()可以做到跨同一个大域下的两个子域。
CAS框架:CAS(Central Authentication Service)是实现SSO单点登录的框架。
Spring Security + CAS实现单点登录
八、单点登录的安全性
应该说单点登录是门户系统的核心组件之一.也是门户系统的安全屏障。通过单点登录验证成功后,用户可以访问门户下所有应用系统,所以保证单点登录的安全是保证门户系统安全的前提。但是,现有的产品在单点登录的安全性还有一些不足:
(1)安全性考虑不全面
各个解决方案在安全性考虑不是很全面,没有针对门户的复杂性,采用多种技术结合保证门户的安全,例如微软的Passport采用Kerberos认证机制来完成身份认证工作,服务器与用户共事的秘密是用户的票据,服务器在回应时不验证用户的真实性,假设只有合法用户拥有口令字。如果攻击者记录申请回答报文,就易形成重发攻击。
(2)安全兼容性不高
很多解决方案的安全性是建立在对自己产品标准的兼容基础上的,对异构的系统安全性支持不好,例如IBM的WebSphere则过于依赖于WebSphere Domino环境,对其它异构系统的安全兼容性不好。
(3)信息传输缺乏安全保证
在门户服务器与应用服务器通信过程中大多数方案采用明文形式传送敏感信息,这些信息很容易被窃取,致使重要信息泄露。另外,在通信过程中大多数方案也没有对关键信息进行签名,容易遭到伪装攻击。
(4)Web服务的安全缺陷
由于单点登录基本上是基于Web服务实现的,所以单点登录天生就继承了Web服务的安全缺陷,这也往往被各个解决方案所忽略。
首先应该避免用户凭证的COOKIE泄露,在用户端,因为内存COOKIE比文件COOKIE更难被截取,特别是经过特殊处理的浏览器,要截取内存COOKIE几乎不可能,而且当浏览器关闭时,内存COOKIE失效,所以应该使用内存COOKIE而非文件COOKIE,这也是很多使用文件COOKIE的论坛帐号经常被盗的原因。
为进一步减少风险,不应该在COOKIE中直接保存用户凭证,而是使用一个无意义的标识符如UUID来表示,而登陆服务可以通过这个UUID查找到真正的用户凭证,这个标志符随机生成,即使同一用户登陆,得到的UUID也不一样,所以不能重复使用,这样即使偶尔泄露一次,也不会造成长期影响。为了提高COOKIE的截取难度,可以设置一个有效时间,只有在有效期内的COOKIE是合法的,超过有效期的COOKIE将被忽略,使用超过有效期的用户依然需要重新输入验证信息。这样也带来一个不便的地方,就是用户如果两次业务逻辑之间的切换时间超过了COOKIE的有效期,那么用户还得重新输入验证信息,达不到单点登陆的效果,所以如何取舍,要根据业务逻辑而定。
其次因为http使用明文传输,通过网络侦听的方式很容易获取COOKIE,所以用户到登陆服务间的连接应该采用https
登陆代理中使用COOKIE来保存SESSION的情况,这是大多数Web应用服务器采用的方法。这种情况类似登陆服务使用COOKIE来保存用户凭证,典型的欺骗是黑客B截获了正常用户A的SESSION COOKIE,然后B访问业务逻辑时附带这个COOKIE,Web应用服务器会认为B就是A,于是A能得到的用户凭证,B也能得到,B就成了A的影子,与A具有相同的操作权限。所以关键问题还是如何避免SESSION COOKIE的泄露,因为这个COOKIE由Web应用服务器控制,所以除了在网络传输时使用https,基本上没有其他办法可以降低风险。除了使用COOKIE作为SESSION标记,很多Web应用服务器也支持隐式域的方式,就是Web应用服务器在页面自动创建一个隐藏的表单项作为SESSION标记,页面提交时该表单自动被提交,Web应用服务器通过这个表单项来确定用户SESSION。这个是更不安全的做法,因为很多很简单的方法就可以获取页面表单项的数据,比获取内存COOKIE容易很多。
业务逻辑、登陆代理、登陆服务间存在消息传递,业务逻辑和登陆代理部署在一个Web应用服务器中,消息传递比较安全。登陆代理和登陆服务通常处在不同的Web应用服务器中,并且通常在地域上也不一致,登陆代理和登陆服务间的安全隐患除了消息泄露,还有相互信任的问题。
九、单点登录中的其他问题:比如令牌如何生成
目前已实现单点登录的典型模型有经纪人模型、代理模型、代理和经纪人模型、网管模型和令牌模型等,比较成熟的解决方案有微软的 Passport、IBM的WebSphere Portal Server、CAS,这些产品虽能较好的实现单点登录,但存在系统复杂、使用成本和学习曲线高、不能满足小型应用系统集成等缺点。
小型系统的令牌用UUID?