统一身份证自定义协议(2)
上一篇文章介绍了自定义协议,但是从某种角度来看,上面的自定义协议并不是一个完全可靠的协议,为何?待我慢慢道来。
简单的来讲,统一身份认证应该分为两块,一是身份认证,一是统一认证(可以理解为sso),如果要集成多协议,比如SAML、CAS,是在统一认证进行集成,而不是身份认证。
图1
- 1)何为身份认证,我们从图1 的过程来阐述。假设用户没有登陆过任何系统,某用户访问sp1,sp1检查发现该用户没有登陆过,即重定向到Server。Server返回一个页面让用户输入用户名、密码等,然后提交表单到Server进行验证。红色部分即为身份认证的过程。为什么,因为对于CAS、SAML协议来说,不关注用户的身份认证的过程,而是关注步骤6返回的内容是否是符合某个协议格式的内容(当然内容是加密过的)。当该用户访问sp2时,sp2发现该用户没有登陆过,重定向到Server,Server检查发现该用户已经认证过,即生产相应格式的响应到sp2,sp2检查校验通过,即可访问sp2,而这个过程可以理解为统一认证过程(简单的来讲就是抛开步骤3的过程)。
- 2)在有前面的基础后,我们来阐述为什么自定义协议1并不是一个可靠的协议,到底不可靠在哪?问题出在了身份认证过程中,即步骤3以后的操作,我们知道步骤3会发起一个身份认证的请求,而Server并不能认证身份,而是将请求进行封装加上自己的签名交给了Engine进行认证,认证后返回UA票据,而Server根据持有的UA票据向Engine申请SP票据和Server票据(我们知道sp票据是Engine用sp的公钥进行签名加密的,Server票据是Engine用Server的公钥进行签名加密的),问题就出在这里,这里导致了Server的权限过大,Server不能为sp进行签名,如果Server要求Engine为非sp签名的请求进行签名加密,即产生了伪造。举个简单的例子来说:有A、B、C三人(A可理解为sp,B为Server,C为Engine),C负责印章,当A来盖章的时候,C认识A,C识别到A允许签名盖章、B来盖章的时候,C认识B,C也可以为B签名盖章,但不允许B在没有A的委托下为A进行签名盖章(即B跟C说为我盖个A的章吧,这是不允许的)。换个更简单的例子就是使用银行卡消费时,只有本人签名才有效,不能说A消费时签B的名,这不符合安全的理念。现在我们来改进自定协议1,让它变得更安全。
1.原理和协议
结构上,自定义协议还是包括SP、IDP Server和IDP Engine三部分。这时候我们需要建立一个信任体系,我们认为IDP Server是可信的。
第一步,sp、IDP Server和IDP Engine都有自己的身份的,所以我们首先得认证自己和对方,但是我们的信任体系的建立是我们认为IDP Server是可信的。
第二步,SP和IDP Server需要向IDP Engine注册生成自己的编号和**。
如下图所示:
图2
协议交互流程如下:- 1.SP初始化的时候,因为信任体系是信任Server,SP的统一认证交给Server,这时候需要建立一个SP和Server之间的共享**。如何申请?SP用自己的**签名向Server发起一个代理向Engine申请共享**的申请(为什么是向Engine,因为只有Engine知道sp和Server的**,也只有Engine能产生共享**,相当于就是Engine就是sp和Server信任的桥梁,共享**是有时间限制的,一般来讲一天)
- 2.Server认证不了请求的真实性,于是加上自己的签名将请求转发给Engine,Engine认证该请求来自SP和Server(因为Server加上了自己的签名),认证通过,生成共享**,分别使用sp的**和Server的加密返回给Server和sp,于是SP和Server持有了sp和Server之间的共享**。
- 3.UA访问SP,SP判断该用户是否已经登录,如果没有登录,SP产生认证请求;如果用户已经登录,直接响应结果。
- 4.SP重定向到IDP Server,URL带有AuthnRequest参数,如果已经登录,跳转到5;如果没有登录,返回登录页面,进行认证操作。
- 5.UA输入用户密码等生成身份认证请求,URL带有CredentialsRequest参数。IDP Server接收到认证请求后,首先判断请求的合法性。然后判断该用户是否已经成功单点登录。如果用户登录过,则IDP Server使用sp和IDP Server的共享**生成响应到sp;如果未登录过,则跳转到4。
- 6.IDP Server将CredentialsRequest请求参数包装成Credentials加上自己的签名向IDP Engine发出身份认证请求(IDP Server需要向IDP Engine认证自己的身份,相当于sp委托IDP Server 向IDP Engine认证自己的身份),如果认证通过,IDP Engine 使用 IDP Server的**加密结果并返回给IDP Server。
- 7.IDP Server根据请求协议将IDP Engine返回的结果包装成不同的协议并将其使用sp和 IDP Server之间的共享**进行加密返回给sp。
- 8.SP检查验证密文。
2.安全性
1.保证了只有SP的请求才能让Engine为SP签名,不会出现IDP Server权利过大的问题保证安全,解决了自定义协议1的存在的不足,安全性更进一步提高。
2.将身份认证和统一认证分开,更容易集成多协议的支持。
3.设计实现
3.1数据交互方式
通过URL传递数据。
3.2参数格式
3.2.1. AuthnRequest
内容 |
由SP属性集合、callbackURL、签名组成 注:CallbackURL不是必须,可以使用IDP Engine注册的默认callbackURL |
格式 |
Sp属性集合 1、Sp编号:sp 元素之间以“;”分隔,key与value之间用“:”分隔 比如:sp:12345;authnReqID:abc123;sign:signValue callbackURL:service 签名:对请求属性使用共享**进行加密
请求格式组成 req=请求属性格式&service=callbackURL |
编码 |
Base64,在网络以Base64编码传输 |
内容 |
由请求属性集合,签名和callbackURL组成 |
格式 |
l请求的属性主要有: 1、身份(由用户名和域组成,格式: 用户名@域): principal 2、当前时间:time 3、票据类型:type 4、随机数标识:nonce 5、IDP Server代理:agent 6、引用: reference 7、sp编号:sp 格式:time:x;type:x;principal:x;nonce:x;agent:x;reference:x;sp:x 元素之间以“;”分隔,key与value之间用“:”分隔 l签名,对请求属性用私有**加密生成密文,格式: sign=加密算法:密文 私有**由用户名、域和密码 md5而成,格式 域 + ":" + 用户 + ":" + 密码 lcallbackURL:service
请求格式组成 req=请求属性格式&sign=签名&service=xxxx |
编码 |
Base64,在网络以Base64编码传输 |