基于Cookie的SSO

26

如何实现一个基于cookie的单点登录而不需要SSO服务器?我希望只使用浏览器上的cookie在多个应用程序之间共享用户已登录信息。

我的想法是这样的:

  • 用户登录一个应用程序
  • 该应用程序验证凭据,然后在浏览器上设置一个存储用户名的cookie(可以用私钥编码)
  • 如果用户打开另一个应用程序,则搜索该cookie并读取其中的用户名值(使用密钥解码字符串)

在这种解决方案中,用户可能会看到浏览器cookie(来自另一个用户),并获取用户名的编码字符串。然后他可以将其添加到自己的cookie中(不好!)。

是否有一些安全的方法来解决这个问题?是否可以使用基于时间戳的控制或类似的东西?

谢谢您提前。

再见

P.S. 我知道我的英语不是很好...对此表示抱歉!

6个回答

20

这是不可能的。 Cookies 是每个域名独有的,一个域名无法读取另一个域名的 Cookies。


+1 是的,跨域 cookies 不被允许,而且通常也不是一个好主意。 - Chris Ballance
即使我设置不同的域名(如果可能的话),也可以吗? - frengo
1
你不能设置一个不同的域名。 - Quentin
5
浏览器不允许这样做。想想看这有多危险——一个恶意网站能够为你的在线银行设定cookie... - JonoW
我不知道这个东西。感谢所有的评论。 - frengo
30
如果域名有一个共同的主域名,那么可以共享Cookie。foo.example.combar.example.com可以共享.example.com的Cookie。 - regilero

10

我觉得答案有点晚了,但也许我能帮助到某些人。

你可以使用 iframe 在一个中间域名上设置 cookie/localStorage,并将其连接到主页。

跨域单点登录

1)登录 在任何一个您的域名上的登录表单通过事件(postMessage)向 sso.domain.com 存储标识令牌到 cookie 中。 2)验证 domain1 和 domain2 包括指向 sso.domain.com 的 iframe,该 iframe 读取令牌并通知主页。

为了简化开发过程,我们最近发布了一个具有 JWT 的跨域 SSO,网址为:https://github.com/Aralink/ssojwt


1
无意中在SO上找到了你的答案,使用iframe解决方案并提供了良好的解释。为两个答案点赞!https://dev59.com/R1oU5IYBdhLWcg3wV18Z#37565692 @pedrofb - David

8

有一种简单的解决方案,不需要使用SSO服务器,但不能使用1个共同的cookie,因为我们知道cookie在不同的域名之间不共享。

当用户在site-a.com上进行认证时,在site-a.com域上设置一个cookie。然后在site-b.com上,您链接来自site-a.com的动态JavaScript,由服务器端脚本(php等)生成,该脚本可以访问创建的cookie,然后使用js在客户端上复制相同的cookie到site-b.com。现在两个站点都有相同的cookie,无需要求用户重新登录。

您可以使用一种加密/编码方法对cookie值进行加密/编码,以便site-a和site-b都知道如何进行解码,以便site-b将能够验证其cookie副本。使用一个共享的秘密,如果没有这个秘密,就无法进行编码或解码。

您可以看到,在site-b.com的第一次页面加载中,cookie不存在,因此如果需要,您可能希望在设置cookie后进行页面重新加载。


有趣,但是 site-a 如何知道要返回哪个会话给 site-b?它需要通过链接将数据从 site-a 传输到 site-b 吗?例如,href=site-b.com?sessid=fivghv6775ghffh? - Martyn
4
会话 cookie 应始终设置 HTTP-only 属性以防止它们通过 JavaScript 被读取。这可以防止会话被 XSS 或 JavaScript 注入漏洞所窃取。如果启用了该属性,则此解决方案将无效。 - LordOfThePigs
2
存储会话 ID cookie 并通过 JavaScript 访问具有巨大的安全风险。此类 cookie 应为“仅限 HTTP”。 - ravi404

3
我做过类似的事情。有一个PHP应用程序,用户登录后,系统联系Web服务,然后服务检查Active Directory上的用户凭据。当用户经过身份验证时,他的PHP会话存储在数据库中。另一个Web应用程序可以从cookie中读取PHP会话,并在PHP应用程序中查询Web服务,PHP应用程序检查数据库中的会话并返回用户ID。通过这种方式,我使用SOA实现了SSO。
不要依赖存储在浏览器中的用户ID,这是一种安全错误,至少要加密ID。
最好的解决方案是将登录表单和会话存储放在同一个应用程序中,然后该应用程序可以为其他应用程序提供服务。
对于此类信息交换,请使用HTTPS。
仅当cookie属于同一域时才能读取cookie,例如:
intranet.example.com crm.example.com example.com/erp

2
你可以跨子域名访问cookie,但我认为使用浏览器cookie并不是一个好的解决方案。实现单点登录并不需要一个“SSO服务器”,很容易想出一个负载,两个应用程序都能识别。我见过使用XML通过HTTPS传输负载的自定义SSO解决方案。

你能更好地解释一下这个解决方案吗? 谢谢! - frengo
当发出一个cookie时(如果您一直在使用Web堆栈的功能来为您编写cookie,而不需要问您太多问题,那么您可能需要动手解决一些问题),只需输入“.yourdomain.com”作为域名,而不是“yousubdomain.yourdomain.com”,任何子域都可以读取它。 - Josh Pearce

0

以下是一个方案(希望在这里得到安全专家的严密审查):

让每个域在类似的cookie中存储用户数据。当用户想要从一个域跳转到另一个域而无需在新域上进行身份验证时,提供一个带有加密令牌的“跳转链接”作为查询字符串。新域将解密cookie并确定用户身份,然后为该域发放新cookie。您需要使“跳转链接”具有非常短的过期日期,因此不应将它们直接生成到页面中,而是生成指向“跳转链接”生成器和重定向器的链接。

这可能并非必要,但是“跳转链接”的接收页面可以向来源域发出Web服务调用,以验证加密令牌的真实性和是否已过期。

我认为这个解决方案容易受到中间人攻击(不确定它是否比当前流行的其他身份验证机制更容易受到攻击),但是您可以将客户端MAC地址和IP地址合并到加密令牌中以获得额外的安全性。


在这种情况下,用户必须点击一个特殊的链接才能跳转到另一个网站,对吗?我不想要它。 - frengo
这是正确的,然而这几乎是实现跨域身份验证的唯一方法。 - Josh Pearce

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接