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

Posted

技术标签:

【中文标题】如何创建跨域共享登录服务?【英文标题】:How to create a Shared Login Service across Multiple Domains? 【发布时间】:2011-05-17 10:38:41 【问题描述】:

我对如何实施共享的跨域登录系统以及要采取的最佳做法和安全预防措施感兴趣。如果您熟悉 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 目的。 cookie 中的一些数据以及 GET 参数 sig 使用 base64_decode 部分解密为以下内容:

// 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[��:

影响..."

编码破坏了代码块。感谢您的帮助!

【问题讨论】:

OpenID、Facebook、OAuth 或 Google 等预打包的共享登录服务是否适合您?或者,您绝对需要自己的共享登录服务吗? 【参考方案1】:

您是否尝试过类似Charles 的方法来嗅探来回发送的内容?它也许可以为您进一步分解。

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

【讨论】:

【参考方案2】:

我认为你 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 将接受他作为该用户。

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

新问题:即使有人猜出您用户的 GUID 的可能性很小,但他的 GUID 仍然会被看到此链接的某个中间人劫持,并且有人会得到他可以永远使用它的 guid。

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

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

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

因为您不想永远向这个 nonce 表添加记录,所以习惯性地决定这样的链接仅在其创建后的某个给定时间内有效。因此您可以创建比此时间限制更早的 nonce 记录。

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

艾尔

【讨论】:

为了进一步实现共享密钥:为共享登录系统中的每个域添加包含公钥/私钥对的配置变量。如果所有盒子上的签名验证方法都相同,您可以验证签名,甚至可以使用 mcrypt() 或等效库来传输双向加密数据,以在验证签名之上提高安全性(其中签名本质上是数据的校验和)。 为什么不只使用随机数(链接到后端的会话 ID)?我的意思是创建一个令牌(可能 1-2 分钟到期,只能使用一次),它链接到后端的会话 ID,所以当我在 site2 上使用它时,服务器可以从数据库中获取会话 ID,擦除令牌并将 cookie 发送回浏览器,为浏览器提供与站点 1 相同的会话。这种方法有什么缺点? 至少有一个不同之处在于,在每次黑客攻击时,您都必须访问数据库,这比验证数据是否已正确签名然后只去如果确实正确签名,则数据库。 您还可以拥有 nonce 和 nonce 的签名版本,以便 site2.com 可以验证签名,如果可以调用 sso 服务器。这个替代方案怎么样? 我不确定我是否理解你的问题,正如我写的(大约 6 年前:)),nonce 应该是传递参数的一部分。因此,在创建签名时应考虑到这一点。 (这样它就不能被中间人操纵。也就是说,我也可以看到有利于不签署现时本身的有效观点......【参考方案3】:

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

【讨论】:

【参考方案4】:

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

在过去开发和管理过一个实施(我们最终选择了 SiteMinder,但我猜你不想要真正产品的成本),我认为 Eyal 有一个非常好的想法,但我d 对其进行一些调整。

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

【讨论】:

【参考方案5】:

您可以尝试实施 Global Network Auto-Login 解决方案 à la Stack Overflow。 Kevin Montrose here 发表了一篇关于其出色实现的有见地的帖子。

这需要 Cookie、html5 localStorage、javascript、Iframe 和大量安全检查,但我认为这是值得的。

【讨论】:

【参考方案6】:

为什么不为此目的使用 Open ID。

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

【讨论】:

Open ID 是一种很好的身份验证方式,但它并不能解决跨站问题。即,如果您使用您的 Open ID 登录到 siteA.com,您仍然需要上述方法来创建您现在也登录到 siteB.com 的情况。顺便说一句,如果您希望能够使用常见的社交网络进行身份验证,您还可以使用 gigya.com 提供的解决方案(我最近还在工作) - 但同样 - 这并不能解决您将要跨域的问题必须自己处理。【参考方案7】:

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

【讨论】:

以上是关于如何创建跨域共享登录服务?的主要内容,如果未能解决你的问题,请参考以下文章

单点登录认证原理及跨域cookie共享

[转]session 跨域共享方案

如何使用 Joomla 作为服务器配置跨域资源共享 (CORS)?

跨域共享cookie

NodeJS 应用程序如何使用 HTTP 请求从禁用的 CORS(跨域共享)服务器访问资源?

如何使跨域资源共享 (CORS) 发布请求正常工作