我正在为一些开发实施一组RESTful服务,其中一项是身份验证服务。
此身份验证服务对两种身份进行身份验证:
这些RESTful服务 无状态 。
当客户端应用程序针对身份验证服务进行身份验证时,或者人员或计算机使用凭据进行身份验证时,这两个操作都会生成 AppToken 和 UserToken 分别。
这些令牌是盐渍哈希,因此对RESTful基础架构的后续请求将在不共享 AppKeys 和凭据的情况下进行身份验证。
从完全无状态的方法的角度来看,这些令牌不应该存储在服务层中的任何位置,而是存储在某种客户端状态(fe,Web客户端将使用 HTTP cookie存储它< / em>的)。 这是我目前正在实施的工作方式。
因为使用这些令牌重新验证每个请求并让服务层接收来自客户端的令牌,因此它可以比较来自客户端的令牌和< em>检查它是否是在服务层重新生成它的有效令牌并与客户端拥有的令牌进行比较太贵了,我实现了服务层 AppToken 和< strong> UserToken ,都具有过期日期和所有者(为其创建令牌的应用程序或用户),以便检查来自客户端的令牌是否存在于令牌存储中。
客户端如何以交互方式取消身份验证? 仅丢弃客户端安全状态。如果它是一个Web客户端,它会丢弃身份验证cookie,只刷新页面,客户端检测不到身份验证cookie,用户被重定向到登录页面。
从RESTful服务的角度来看,这是一个无状态的未经身份验证:客户端不了解具有服务层伪身份验证状态的技巧。 这只是服务实施细节 - 性能优化 -
我不打算列出无状态服务的 pros ,因为我绝对相信这种方法是可行的,但我发现了一个问题:无状态身份验证/取消身份验证意味着客户端不会通知服务器他们关闭会话,因此安全存储以大量无用的记录结束。
如果服务客户端的会话时间有限(fe,1小时,3小时,一天......),那么这不是一个大问题,但如果用户必须通过身份验证会发生什么? em>永远(8个月,一年)?。 如何区分什么是过期的令牌?
有一些方法可以解决这种情况:
每当服务层收到请求时,它都会更新令牌到期日期,因此自动流程可能会删除那些已过期的令牌,这些令牌定义了令牌的任意过期(24小时)。
妥协体系结构的无状态特性,让客户端通知服务层他们不再需要进行身份验证,因此服务可以将关联的令牌丢弃到客户端会话(但是等等......如果客户端关闭Web客户端会发生什么?用户永远不会主动通知服务必须丢弃令牌......所以......僵尸令牌已经存在,所以自动化流程应该删除它们,但是。 ..什么是僵尸令牌?我不喜欢这种方法)。
完全无状态身份验证,无存储,每请求身份验证。
这是个问题!您的建议方法是什么 - 即使它不是1.,2。或3. - 为什么?
感谢您长篇大论 - 我真的相信这个问题的结论对任何人都非常有用 - !
答案 0 :(得分:7)
无状态身份验证,基于令牌。假设传输级加密。
[X]SS
- 由S的公钥签名的X [X|Y]
- 同一信封中的X和Y Y [M]SY -> S
- Y将签名消息M发送给S。<强>目的:强> 客户C希望与服务S交谈。
客户端C向服务A发送其共享密钥或公钥PKC
以进行身份验证,其中C知道端点和公钥(PKA
)。
A [now + interval | user-id or PKC]SA -> C
说明:
服务A将当前日期/时间的间隔添加为到期日期。在要发送的缓冲区中,现在是到期日期和用户ID PKC
(假设您拥有有效的身份提供商)。
[now + interval | user-id or PKC] = T
有迹象表明;
[T]SA
客户C希望与后端服务S进行对话。
C [[M|[T]SA]SC -> S
C将消息M加上从A签署的令牌发送到服务S。
S关心C确实发送了它并验证了C从签名中读取的签名SC
。
验证令牌的签名SA
。失败意味着请求被拒绝。
验证令牌[T]SA
:用户ID / PKC
正确且令牌日期&gt; =现在。过期令牌意味着向客户端C发送“令牌过期”消息。如果令牌有错误签名,则权限被拒绝。
(可选; S授权C,题外话)
S执行工作并将[M2]SS
发送回客户端C.
这不会太多开销;验证签名是一个非常快速的操作。
问题“C# Sign Data with RSA using Bouncy Castle”会显示您如何签名并验证一段字符串,即您要发送的邮件。
你需要证书;如果您正在使用配置管理器(您应该这样做!;)),如木偶,那么您create a certificate signing request (CSR)然后sign it using puppet。
有一种称为证书撤销请求的东西,它基本上是已被撤销且不被信任/使用的公钥的清单。将PKC
放在那里并广播撤销,它基本上是要求客户端进行另一个证书签名请求轮。
此外,如果您希望能够使特定令牌过期,请在创建令牌T
时为其添加唯一ID(UUID / GUID),并拥有令牌撤销列表,类似地在更改时广播,用于清除令牌过期时的令牌UUID。因此,如果收到的T在其中,服务也会检查令牌撤销列表。
看看软件巨头正在做的事情。例如。亚马逊的REST界面,使用共享密钥:
Amazon S3 REST API使用基于keyed-HMAC的自定义HTTP方案 (哈希消息认证码)用于认证。进行身份验证 请求,您首先连接请求的选定元素 形成一个字符串。然后,您可以使用AWS Secret Access Key进行计算 该字符串的HMAC。非正式地,我们称这个过程是“签署的 请求,“我们称HMAC算法的输出为”签名“ 因为它模拟真实签名的安全属性。 最后,使用将此签名添加为请求的参数 本节中描述的语法。
答案 1 :(得分:-1)
选择的方法:完全无意识的认证和无法认证
最后,我得出了一个结论和协议,以便切换到完全无状态的基于令牌的身份验证和未经身份验证。
如何实现?
首先,您需要为应用程序提供无状态基于令牌的身份验证(但用户身份验证将以相同的方式工作,不包括此清单):
这是验证应用程序的流程:
客户端向身份验证服务发送身份验证请求。此请求必须包含应用程序密钥(AppKey)。
验证服务接收先前发送的请求。
现在,身份验证服务会创建一个应用程序令牌(AppToken),它是一个自我描述的连接,用于跟踪具体经过身份验证的客户端到依赖于身份验证服务的服务。< / p>
AppToken 是一个复合字符串(此组合可以是使用JSON序列化的对象):
身份验证服务加密步骤#4结果(JSON序列化对象)。 **使用AppKey作为对称密码的密钥或密码。就我而言,我将使用Rijndael。
后续请求将包含此令牌,以避免发送纯文本凭据。这些请求也将始终包含 AppKey ,因此身份验证服务将能够识别正在尝试对请求进行身份验证的应用程序。
一段时间后,令牌变为过期或无效,并且客户端请求新的AppToken。或者客户端被用户关闭,并且没有可以保存安全令牌的持久存储,因此下一个客户端会话将在需要时请求新的。
有关此类身份验证方法的.NET实现的一些提示和详细信息:
我使用System.Security.Cryptography.RijndaelManaged
类进行对称加密。 AppKey和AppToken(以及在基于令牌的用户身份验证的情况下,它几乎是相同的解决方案)都是使用RijndaelManaged
类生成的。
加密文本转换为HEX字符串。这是与身份验证响应一起发送的。在我们的例子中(RESTFul API),表示 AppToken 的HEX字符串将作为响应头发送。每当请求包含此HEX字符串时,身份验证过程会将其重新转换为原始加密文本,稍后它将被解密以评估令牌是否有效。
感谢Henrik的努力。我在你自己的答案中采用了一些概念,并将它们与我自己的结论混合在一起。