有没有办法让一个人在跨子域的 firebase 上进行身份验证
Posted
技术标签:
【中文标题】有没有办法让一个人在跨子域的 firebase 上进行身份验证【英文标题】:Is there any way to keep a person authenticated with firebase across subdomains 【发布时间】:2017-12-17 01:21:22 【问题描述】:我在我的网站上使用 firebase 进行身份验证,并且我希望跨子域保持用户身份验证会话处于活动状态。
不幸的是,firebase 使用本地存储来存储用户的会话。不幸的是,它独立于每个子域。
我已经知道您可以使用 firebase 从服务器端生成 JWT 令牌,但它不允许用户退出站点,因为用户最终仍会登录其他子域。
【问题讨论】:
【参考方案1】:在花了更长的时间之后,我打算让单点登录跨子域工作,I wrote up a blog post 详细说明了如何实现这一点。
作为高级概述(忽略了重要的安全细节):
我们在不同的领域有三个应用程序。
accounts.domain.com
app1.domain.com
app2.domain.com
我们有三个 Firebase 函数
...cloudfunctions.net/users-signin
...cloudfunctions.net/users-checkAuthStatus
...cloudfunctions.net/users-signout
为了登录:
-
有人导航到
accounts.domain.com
应用
他们提供身份验证信息
该身份验证信息被发送到我们的 /users-signin
云函数,该函数会验证信息,如果有效,则会设置一个签名的 __session
cookie,其中包含用户的 UID 并向客户端返回成功指示。
成功后,客户端调用/users-checkAuthStatus
云函数,查找签名的__session
cookie,提取用户UID,并使用UID 和firebase-admin SDK 生成自定义身份验证令牌并返回客户。
当客户端收到此自定义身份验证令牌时,它会使用它通过 firebase javascript SDK 登录。
当有人导航到其他应用程序之一时,例如app1.domain.com
,该应用程序首先会检查此人是否已使用 firebase javascript SDK 登录。
-
如果是的话,太棒了。
如果没有,它会调用
/users-checkAuthStatus
云函数,该函数会查找签名的__session
cookie,如果找到有效的__session
cookie,则将自定义身份验证令牌返回给客户端。
如果返回自定义身份验证令牌,客户端会使用它通过 firebase sdk 让用户登录。
如果未返回自定义身份验证令牌,则表示用户未通过身份验证。然后,您可以选择将它们重定向到身份验证应用以登录。
同样,这是一个高级概述,忽略了跨站点脚本攻击、实际退出等问题。有关更多信息,check out the blog post。
【讨论】:
你能看看我的问题吗?我现在几天都解决不了***.com/questions/63424850/…【参考方案2】:这是正确的。 Firebase 仅支持单主机源会话。 Firebase Auth 正在研究支持 cookie。目前还没有简单的解决方案。随时在 Firebase 论坛申请此功能:https://groups.google.com/forum/#!forum/firebase-talk
目前,如果您真的需要这个,这里有一个相对简单的选择: 创建一个接收 Firebase ID 令牌并基本上为其底层用户返回自定义令牌的端点(您需要使用 Admin SDK 来执行此操作,然后验证 ID 令牌,获取用户 UID,然后生成自定义令牌)。用户登录的子域会将 ID 令牌传递给用户仍未通过身份验证的另一个子域(您可以使用 iframe 跨源 postMessage 来传递它,或者只是将该 ID 令牌保存在 *.domain.com 策略中) .然后,自定义令牌可用于使用自定义令牌进行 signInWithCustomToken,从而有效地在此页面上登录同一用户。
这是有风险的,因为端点可能会暴露漏洞(它将短期令牌转换为无限期令牌)。如果 ID 令牌泄露,攻击者基本上可以作为利用此端点的用户登录。
【讨论】:
感谢您的回答。您对减轻这种风险有什么建议吗?我的印象是自定义令牌无论如何都会在一个小时内到期,所以它仍然很短暂。 问题是任何持有 ID 令牌的人都可以通过您创建的自定义令牌端点将其转换为无限期会话。要缓解,请检查 ID 令牌中的auth_time
以确保用户最近登录。这会缩小攻击窗口。
另一个问题。通过 postMessage 传递 ID 令牌似乎很不安全,因为来自另一个扩展的任何内容脚本都可以收听该消息。因此,鉴于您不只是将其发送回另一个子域,而是发布它以供所有内容脚本查看,因此 ID 令牌可能被泄露的担忧很有可能。我是否遗漏了什么,或者这也是需要考虑的安全风险。
什么意思?您正在将消息发送回您拥有和信任的域。如果您拥有的域上存在恶意脚本,那么您需要担心更严重的问题。
如何在登录域上使用一个非常短暂的会话cookie而不是使用postMessage,然后登录域将接受一个与会话cookie匹配的自定义令牌的GET请求? GET 请求可以对受信任的域强制执行 CORS 策略。这种方法的好处是登录可以通过重定向而不是弹出窗口或 iframe 进行。【参考方案3】:
iframe 不再适用于 Safari,因为它不再让 iframe 的原始页面访问其自己的 indexeddb。这意味着您无法获取 id 令牌,onAuthStateChanged
将始终返回 null
。
我们实施了另一种解决方案,我们将自定义令牌与重定向信息一起存储到安全 cookie 中,将用户重定向到另一个域,使用 cookie 登录或注销用户,删除 cookie 并重定向将他再次转到存储在 cookie 中的位置。
-
登录
获取自定义令牌
使用“signIn”或“signOut”动作、redirectUrl 和令牌(如果登录)设置 cookie
重定向到其他页面
登录或退出
删除 cookie
重定向到redirectUrl
这又适用于 ios 和桌面 Safari。但它只有在同一个域中才有效,这样两个子域都可以访问该 cookie。
【讨论】:
【参考方案4】:Firebase 现在似乎支持内置 cookie,因此您应该能够按照这个新指南跨子域使用它:
https://firebase.google.com/docs/auth/admin/manage-cookies
【讨论】:
【参考方案5】:我使用 nginx 加载想要共享相同 firebase 身份验证的不同网络应用程序 如果域或子域相同,那么它在 firebase 中开箱即用。
server
root /var/lib/jenkins/workspace/app/dist;
index index.html index.htm index.nginx-debian.html;
server_name app.com; # example
location /app1
alias /var/lib/jenkins/workspace/app1/dist;
try_files $uri $uri/ =404;
location /app2
alias /var/lib/jenkins/workspace/app2;
try_files $uri $uri/ =404;
location /static
alias /var/lib/jenkins/workspace/build/static;
try_files $uri $uri/ =404;
location ~ /\.ht
deny all;
listen 80;
listen [::]:80;
【讨论】:
以上是关于有没有办法让一个人在跨子域的 firebase 上进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章