如何跨多个域创建共享登录服务?

问题描述 投票:30回答:7

我对如何实现共享的跨域登录系统以及最佳实践和安全预防措施感兴趣。如果您熟悉37Signals,您可能习惯于使用共享通用身份验证机制,如果您使用顶级导航到其他产品,则无需随后登录。我想以类似的方式实现一些东西。

我在网上找到的最接近的东西是关于Central Authentication Service的维基百科条目以及对Cross Domain Login - How to login a user automatically when transfered from one domain to another的回应,在这种情况下可能略有不同。

我已经检查了他们的会话cookie,以便掌握他们在此过程中所做的工作。最初,每个产品链接都有一个“goto”uristub,即:

https://MY_COMPANY.campfirenow.com/id/users/[int_identifier]/goto

使用FireCookie和Firebug中的NET选项卡,我能够看到设置的cookie以及过程中出现的重定向。 goto url触发302重定向到:

https://MY_COMPANY.basecamphq.com/login/authenticate?sig=[BASE64_ENCODED_AND_ENCRYPTED_DATA]

重新创建会话标识符,最有可能用于CSRF目的。使用base64_decode对cookie中的一些数据以及GET参数sig进行部分解密,如下所示:

// sig GET param
array(2) {
  [0]=>
���ף�:@marshal_with_utc_coercionT7�z��<k��kW"
  [1]=>
  string(18) "���k�<kn8�f���to��"
}

// _basecamp_session cookie session param
string(247) {
:_csrf_token"1Sj5D6jCwJKIxkZ6oroy7o/mYUqr4R5Ca34cOPNigqkw=:session_id"%060c0804a5d06dafd1c5b3349815d863"
flashIC:'ActionController::Flash::FlashHash{:
@used{: auth{"
              MY_COMPANY{:
                       user_idi�3
:identity_idi�W����������s�]��:�N[��:

߾�����"

编码打破了代码块。谢谢你的帮助!

session cookies login shared autologin
7个回答
60
投票

我认为你的Q中的关键是你写的“如果你使用顶级导航到另一个产品,你不必随后登录”。

我将解释:您希望能够从site1.com移至site2.com并让site2.com知道您是通过site1.com登录的用户。

因为cookie不能在不同的域之间共享(除了子域名,但我猜你不是在谈论子域名),你必须将链接上的一些信息传递给site2.com,让它与后端交谈并知道什么用户你。

让我们从一个天真的解决方案开始,然后以我们的方式解决它带来的一些问题:假设您在某些后端数据库上有一个用户表,并且您的用户有一些ID。现在假设用户在site1.com上进行了身份验证,并且他是来自您的数据库的用户123。最天真的解决方案是调用site2.com/url/whatever?myRealID=123并让site2检查此ID并“相信”用户这确实是他。

问题:任何人(甚至是您网站的有效用户)都会看到您的链接,可以创建myRealID = 123的链接或尝试其他值。和site2.com将接受他作为该用户。

解决方案:不要使用可猜测的ID假设你向用户表添加一个唯一的GUID,如果用户123有一个8dc70780-15e5-11e0-ac64-0800200c9a66的guid,那么请调用site2.com/url/whatever?myGuid=8dc70780-15e5- 11e0-ac64-0800200c9a66。

新问题:尽管有人猜测你的用户的GUID是不太可能的,他的GUID仍然会被一些看到这个链接的中间人劫持,有人会得到他可以永远使用它的指导。

解决方案:使用保存在服务器上的私钥来签署一个包含以下数据项的字符串,当前时间戳,目标站点(即“site2.com”)所述GUID,此签名可以翻译成“这是证明此链接是由网站在上述时间为具有此GUID的用户通过此域进行身份验证创建的“并将其与时间戳和GUID一起发送到site2.com。现在当site2.com获得链接时,他可以确保它已正确签名,如果某个中间人或最初用户会尝试以任何方式更改它(我修改时间或GUID),那么签名将与site2不匹配。 com将拒绝验证用户身份。

最后一个问题:如果链接被中间人拦截,他仍然可以使用其他机器。

解决方案:在传递的参数中添加一个nonce。 nonce只是一个随机数,您的身份验证系统应该确保它不允许您使用此数字进行多次身份验证(因此命名为N(umber)-ONCE)。请注意,这意味着您在site1.com上创建的每个链接都指向site2.com,这些链接应该有一个不同的nonce,需要保存在后端以供以后验证。

因为您不希望永远不断地向此随机数表添加记录,所以可以自定义这样的链接仅在创建后的某个给定时间内有效。因此,您可以创建超过此时间限制的nonce记录。

我希望这是你在寻找的大纲。我可能错过了一些东西,但这些是基本准则,使用签名来证明链接中数据的真实性,并使用随机数来防止中间人攻击。如果可能的话,我还建议使用HTTPS作为这些链接。

的Eyal


5
投票

您可以尝试在堆栈溢出中实现Global Network Auto-Login解决方案。 关于Kevin Montrose here的精彩实施,有一篇很有见地的文章。

它需要Cookies,HTML5 localStorage,Javascript,Iframe和大量的安全检查,但我认为这是值得的。


1
投票

允许用户选择使用他们的facebook / yahoo / gmail / openID解决方案是一个开始,但这并不能完全解决实现或使用自己的解决方案的解决方案。

过去已经开发并管理了一个实现(我们最终选择了SiteMinder,但我猜你不想要真正产品的成本),我认为Eyal有一个非常好的主意,但我会添加一个对它的一点调整。

在身份验证时,生成随机代码(可以是GUID值,但它不是每个用户的静态值)与用户ID一起存储在事务表中。此代码具有最长生命周期(您需要判断该时间段的安全值)。理想情况下,此代码可以使用用户名进行哈希处理,也可以加密并作为URL的一部分发送。


0
投票

你有没有试过像Charles那样嗅到来回发送的东西?它可能能够为您进一步分解。

正如FlipScript所提到的,也许使用OAuth / OpenID可能是你的前进方向?


0
投票

看看Jasig CAS http://www.jasig.org/cas。我认为它会做你想要的。它是开源的,并且有许多插件,允许您使用多个域/语言对多个身份验证源进行身份验证。


0
投票

使用类似.NET Passport(IE.Windows Live Id)的东西或Facebook使用其API进行的方式,可以公开查看。


-1
投票

为什么不使用Open ID。

OperID将是解决此问题的最佳解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.