多域名自动cookie单点登录 - 如谷歌

37

我不明白谷歌是如何实现单点登录的以下机制:

  1. 例如,我登录了Gmail(我想这会创建一个带有我的授权的cookie)
  2. 我打开一个新标签页并直接输入“YouTube”的网址
  3. 然后我进入已经登录的YouTube。

第二个站点如何检测到我已经登录。它们是不同的域名。YouTube无法读取Gmail的cookie。

我读过所有的单点登录解决方案,但它们都不允许这种情况。客户端总是要求中央登录应用程序的权限。在我的例子中,YouTube不知道我是已经登录Gmail的同一用户(实际上它知道,但我不明白怎么做)

请注意,我手动键入“YouTube”的网址。我没有点击Gmail上方工具栏中的YouTube图标(在那种情况下,Gmail可能会通过URL传递某些身份验证参数)。


也许这个 SO 问题中有答案?https://dev59.com/xXVD5IYBdhLWcg3wO5AD - mxro
1
你能找出他们是如何做到的吗?我感到困惑,因为我一直在使用Firebug,如果我已经登录了google.com,那么转到youtube.com从来没有重定向到类似sso.google.com的网址。它不知何故地知道你已经登录了。 - F21
你弄明白它是怎么工作的了吗? - chanchal118
我已经寻找这个答案超过一年了,我得到了一些指向SAML的指针,但基本上与您解释的相同,IDP存储cookie并且用户必须至少重定向到IDP网页才能读取cookie。在YouTube中没有发生重定向。 - George
@James Okpe George,你无法用肉眼看到重定向。你需要使用Web调试器。 - Hichem
5个回答

20

这些 cookies 被设置在特定的域名下。例如:

setcookie(name,value,expire,path,domain) 

当您登录Gmail时,在“ mail.google.com”之前,您会被重定向到“ accounts.google.com”,然后再重定向到“ mail.google.com”,所以Cookie也在“ accounts.google.com”上。

在此情况下,域名为“ accounts.google.com”,路径为“ /”(主目录)。

当您请求“ www.youtube.com”然后单击“连接”时,它会快速请求“ accounts.google.com”,因此您看不到此重定向,并检查您在“ accounts.google.com”上是否具有Cookie。如果是,则检查Cookie是否有效且未过期,或者用户未被禁止……然后将您重定向到“ www.youtube.com/signin?loginthisSession=Sessionid”。此请求包含从“ accounts.google.com” cookie中捕获的sessionid cookie值。

在最后一步,“ www.youtube.com”记录您并在域“ www.youtube.com”上设置自己的cookie并保存它们。

因此,技巧在于302 HTTP重定向。

更新

我不知道为什么人们一直提到iframe。请查看此问题发布于2016年时的日期。Google当时没有使用iframe。正如我提到的,捕获Web流量,您可以看到SetSID,这意味着从accounts.google.dz(com)设置SESSION_ID cookie,然后重定向到youtube.com。它不能通过iframe 不同的域 安全措施在iframe之间无法从一个域重定向到另一个域。也不是请在发布之前阅读此内容。

enter image description here


1
重定向是如何在不使用Firebug的情况下实现的? - chanchal118
@chanchal118 请打开这个截图或通过代理/ httpfox 进行操作,您将会看到。 http://i.imgur.com/aDIcYJb.png - Hichem
@SilverlightFox请打开您的眼睛查看此截图,或通过代理/ httpfox 进行操作,您将看到http://i.imgur.com/aDIcYJb.png。 - Hichem
1
@K3rnel31 这个截图是在登录YouTube时拍摄的吗? - chanchal118
@chanchal118 没错,昨天在同一时间拍摄,自己试试就能看到:)这些请求都是从 302 来的,每个请求都会重定向到另一个请求,直到最终到达 youtube.com。 - Hichem
显示剩余9条评论

5

使用中间域名,可以在不同的域之间共享Cookies和localStorage。主页嵌入了一个"iframe",它访问Cookies并向主要页面发送消息。

mail.google.comyoutube.com可以使用accounts.google.es共享Cookies。打开Chrome->Inspect->Resources->Local storage,您会在accounts.google.com中看到JWT格式的身份验证令牌。

我在这个答案中详细介绍了技术步骤:https://dev59.com/R1oU5IYBdhLWcg3wV18Z#37565692。还可以查看https://github.com/Aralink/ssojwt,以了解在中央域中使用JWT实现单点登录的实现。


2
请注意,在网站之间共享 cookie 的 iframe 被称为“第三方 cookie”,并且在新的浏览器中已经过时,详见:https://blog.chromium.org/2020/01/building-more-private-web-path-towards.html。 - Ng Sek Long
1
似乎这会影响不包含SameSite标签或不使用https的第三方cookie。这会影响跟踪cookie,但不会影响答案中解释的用途,也不会影响localStorage。该内容使用在iframe之间使用postMessage共享,这是一种安全且被接受的方法。 - pedrofb

2

0
据我所记,如果我没记错的话,cookie包含一个指定的字段,其中包含可以读取和获取此类cookie的域。这是为了防止某些网站读取您的所有cookie列表并进行自己的业务。您应该能够看到哪些网站可以“看到”您的gmail cookie。
如果我错了,请纠正我,这应该编译给出关于SID和gmail-YouTube示例的答案。

0

在评估这个跨域SSO主题时,我想到了一个可能使用带有时间戳的cookie的新的SSO同步流。虽然这不是Google使用的流程,但我认为对于具有有限域数的系统来说,这种流程是可行的。

此流程不使用第三方cookie

这将是一篇长文章 :)

域名

为了举例说明,假设我们有以下域名作为我们的示例宠物论坛:

更改为https://account.domain1.com

登录步骤:

  1. 用户访问 dog.domain2.com,但尚未登录。
  2. 用户点击 dog.domain2.com 上的登录按钮。
  3. 用户被重定向到 account.domain1.com 进行登录。
  4. 用户输入用户名和密码,登录成功。
  5. 新步骤:在重定向回 https://dog.domain2.com 之前,在所有域上设置cookie。
    1. 将浏览器重定向到 https://accounts.domain2.com?..
    2. .domains2.com 域上设置cookie(有关cookie值的更多信息稍后提供)。
    3. 将浏览器重定向到 https://accounts.domain2.com?..
    4. .domains3.com 域上设置cookie。
    5. 将浏览器重定向到 https://accounts.domain1.com?..
    6. .domains1.com 域上设置cookie。
    7. 重定向回原始流程。
  6. 将用户重定向回其原始服务,即 https://dog.domain2.com

现在,在登录流程之后,我们在所有三个域名上都有cookie。任何我们的服务(例如https://cat.domain1.com / https://dog.domain2.com / https://rabbit.domain2.com)都可以在其自己的域名下访问此cookie。

Cookie内容

  • Cookie的内容应该允许任何网页查看它,并确定是否需要SSO同步
  • 可以存储不同类型的cookie内容,包括
    • 布尔值表示用户是否已登录
    • 用户ID
    • 过期时间戳

布尔值表示用户是否已登录

用户ID

  • 虽然把user_id存在cookie上面,让所有域都能看到并设置用户看起来很诱人。
    • 但是这太危险了,因为cookie在父域中设置,
    • 如果您域下的任何网站被黑客攻击,可能会发生身份冒充(复制任何一个user_id,将其粘贴到自己的浏览器cookie中)。

过期时间戳

我建议将cookie值设置为SSO过期时间,并将类型设置为会话cookie,这样有以下好处:
  • 如果泄露/更改,过期时间对安全性的影响最小
  • 我们的网站可以检查过期时间以了解用户是否需要重新登录
  • 至于为什么是会话cookie,是因为当用户关闭浏览器并尝试再次登录时,cookie将被删除,因此也会注销用户
任何使用SSO的网页都应该自己存储一个具有相同过期时间的cookie
  • 有些情况下,用户A登录,访问https://cat.domains1.com然后用户B登录
  • 由于用户A用户B将具有不同的登录过期时间,存储并比较该时间戳将告诉用户再次与SSO同步

您的服务的示例检查实现

例如,在https://cat.domains1.com上,您可以将此添加到页面加载的顶部。
<?php
$sso_expired_time = $_COOKIE["sso_expired_time "] ?? 0;
$website_expired_time = $_COOKIE["website_expired_time "] ?? 0;

if( (int) $sso_expired_time  < time() || $sso_expired_time  !== $website_expired_time ) {
    // User not sync, perform sync
    setcookie("website_expired_time", $website_expired_time,0,"/", $_SERVER['SERVER_NAME'], true, true);
    // Redirect to https://account.domain1.com for Login
    // Or, Initiate the login sequence for your selected login protocol
    header("Location: https://account.domain1.com/.....") 
    exit;
}
// User is sync

// Page load success, continue other operation

登出

登出与登录非常相似,基本上:

  • 在登出之前,像登录一样重定向到所有3个域
  • 删除SSO cookie
  • 继续正常的登出流程

方法的优缺点:

  • 优点:所有域同步可能
  • 优点:无需依赖第三方cookie
  • 缺点:首次登录时间较长(大约多50毫秒)
  • 缺点:需要对每个网站进行自定义以使同步工作

在这种实现中,如果一个域名不可用,它不会重定向到下一个域名,而且后续的域名也不会登录/退出,对吗?有没有除了为每个域名打开多个标签页/弹出窗口之外的简单方法来解决这个问题? - Lauro
1
您可以使用此图像技巧检查页面是否正常运行:https://dev59.com/Pm435IYBdhLWcg3wxDFp#63897923。 - Ng Sek Long

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