欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

对单点认证的理解(不是讨论怎么解决) 应用服务器算法浏览器PHP数据结构

程序员文章站 2022-07-08 09:26:45
...
好比你去一个公园游玩,去到每个摊点时却又要你买一次票,是不是很麻烦?
而单点认证就是只要在门口买一次票后,只需在进去时要向摊主展示一下你的门票
,同一个公园内的摊点就任意随你参观了。

即统一一个登录入口,经过验证后发给客户端一张"门票"作为买过票的评据,可以访问所有"公园设施",至于"门票"是怎么保存到游人手上(客户端)的,就是单点认证的核心难点。

很多人说用COOKIE。不错,在B/S模式中,COOKIE可以说是唯一合法的、能主动由服务器存放数据到客户端的途径(SESSION也是由COOKIE来保存SESSIONID的,若是临时的则由当前浏览器进程,SESSION和COOKIE的关系已在另一篇文章里讨论过了)。
但COOKIE有个限制,就是"跨域"问题,即一个站点只能控制以它的根域为名的COOKIE数据,如WWW.W3C.COM则只能控制W3C.COM这个域的COOKIE,其他如GOOGLE.COM、microsoft.com等的它都管不了。

当架设一个单点认证系统时,用户访问应用服务器A(AS.A),AS.A在自己的服务器上找不到有登记信息,则会导向到登录服务器(LS)为用户做登录认证,通过认证后,LS记录下用户的信息,并给AS.A发一个信息说"这个用户买票了",AS.A就在自己的服务器上接收LS传过来的复本作登记了(则以后不用每次都向LS查询),同时回馈给用户一张"票根"即认证根据(TOKEN ID),再把用户导向回AS.A,用户就可以到AS.A上进行他的活动了。

过了会用户在AS.A上玩厌了,想到隔壁的AS.B上看看时,AS.B也要问用户查看他的"票根",这时问题来了。

如果AS.A和AS.B是不同域的,一个是A.COM一个是B.COM,用户(USER)要访问AS.A则只要判断COOKIE里有没"票根"并根据这个"票根"来核对是不是他本人。
这个"票根"对AS.B也是通用的,只要向AS.B展示这个"票根"就行了。但问题正是,"票根"是在通过LS认证后,AS.A存放到A.COM的COOKIE里,而在访问AS.B时,AS.B是不能访问A.COM的COOKIE数据的,或者说它根本不知道A.COM的存在。
(注:A1.A.COM和A2.A.COM这样是同域的,都可以访问A.COM的COOKIE)

所以USER在访问AS.B时又要得到LS做一次认证,这就违反了单点认证的本意。
这就是COOKIE的跨域限制问题。



一个简陋的解决方案是在AS.A的每个连接上都追加一个TOKEN ID(类似&TOKENID=asrw34rzx242),当用户顺着这个连接到AS.B时,AS.B就能根据这个贴在用户脑袋后面的"票根"来向LS做认证查询了,若在LS上有对应TOKEN ID的合法信息存在,则也保留一份到自己的服务器上备用,并且也有样学样在每个连接上贴上这个"票根",好让用户顺着连接到别的"摊点"(AS.C、AS.D.....)上继续游玩。

但这种这方法实现很简单,但有很多缺点,如要求所有认证系统内的页面都要贴上一段TOKEN ID,即不美观又麻烦,而且,当用户不是顺着页面的连接,而是新开一个窗口来访问AS.B时,取不到TOKEN ID的值,也需要重新到LS认证一次。
所以这种做法只适合简单的会话型或一条龙服务型的。

还有一种做法是LS群发,即用户登录后,LS向所有在它名下所有登记的"摊点"都发一次通知,让他们自己做记录。如果用户无聊登录一下又马上退出又登录...,那LS就可能忙得不可开交了,接到通知的AS们也要跟着瞎闹个不停;又假设同时有100人登录,而园内有上100个摊点,LS就要发通知100X100次,真是一百遍又一百变;很有可能一个用户永远只去一个"摊点",其他的一次都没有去过,而其他的也要为他做登记,已供侯用户的"突击访问",这样就比较浪费资源和表情了。
所以这种做法也不是很妥当,适合园子比较小的:)
(后来认真想想也不行,就算每台服务器里都有登录信息了,但用户手上还是没有证明他身份的凭据:TOKEN ID,因此此方案否决!)

一种比较可行的方案:
借用这里了一个很巧妙的思路(纯指思路,代码不成熟)
http://blog.csdn.net/liyujie2000/archive/2004/03/11/13511.aspx?Pending=true

即在访问AS.B时,AS.B得不到TOKEN ID则不是主动向LS查询了,而是"悄悄"地引导客户到LS,再"悄悄地"由LS把客户的TOKEN ID帖到客户的脑后带回到AS.B,AS.B就可以根据根据带回来的TOKEN ID再向LS做一次验证(如此麻烦是为了防止欺骗,当然LS和AS.B之间的会话也要校验),这个过程是"瞒着"客户利用客户的浏览器(就是为了取回LS的COOKIE"票根")悄悄进行的,用户体验上最多在第一次访问时比第一次登录AS.A时慢一点,因为多了一步AS.B向LS校验的过程,但总的来说是简单可行的。
(注1:因为每次合法认证都需经过LS,所以LS的COOKIE是一定存在的,若不存在呢?废话,提示他登录咯。所以LS的COOKIE是这个跨域方案的基础)


能不能不用COOKIE呢?
这跟客户端的身份识别技术有很大关联,如果能确认唯一客户端,那就可以不依靠COOKIE了,这种技术也有不少,但都不是很方便,如客户证书等。另外有人说取用户的网卡的MAC值,如果你能用"合法"的手段做到,那么我也没意见的。


还有COOKIE的一个"伪造"和"顶替"问题(COOKIES欺骗),所谓"伪造"那是知道服务器生成COOKIE的格式和算法,伪造者再重新生成的一个COOKIE,如SERVER A的COOKIE的结构为:USERID = XXX;USERPASD = ****;TOKEN=ASD34AF23SDF3;
TOKEN是根据USERID和USERPASD再加上服务器的私钥生成的一段摘要,
而伪造者只有知道它的私钥和TOKEN的具体算法才能用任意的USERID和USERPASD来伪造一个合法的COOKIE。
而顶替呢,则只需要得到这段"USERID = XXX;USERPASD = ****;TOKEN=ASD34AF23SDF3;"完整的数据,根本不需要知道服务器的私钥和TOKEN的算法,只需把这段COOKIE发给服务器,在SESSION ID的有效期内就能冒充这个COOKIE本身的所有者来与服务器进行会话。
有些人对这两个概念老是混淆不清就一昧地说COOKIE不安全、容易被窃取,那只是看到"顶替"这一方面,但若要随意伪造COOKIE却不会那么容易,如果你能随意得到服务器的私钥(就算TOKEN的算法是公开的),那只能说是那台服务器的管理有问题,你把银行帐号的密码写到本子上锁到柜子里,而柜子被小偷撬开,根据密码到柜员机取走了钱,难道可以说是银行不安全吗?


相关讨论连接(有些思路不是完全正确的,不要随便盲从):
http://forum.iteye.com/viewtopic.php?t=11655&highlight=%BF%E7%D3%F2
http://forum.iteye.com/viewtopic.php?t=11582&highlight=%BF%E7%D3%F2
http://forum.iteye.com/viewtopic.php?t=6473&highlight=%BF%E7%D3%F2