跨子域使用 localStorage

IT技术 javascript subdomain local-storage
2021-02-09 02:04:33

我在可以支持它的浏览器上localStorage替换 cookie (除了 IE 之外的任何人)。问题是site.comwwwsite.com存储他们自己单独的 localStorage 对象。我相信 www 被认为是一个子域(如果你问我,这是一个愚蠢的决定)。如果用户最初在site.com并决定输入www在她下次访问site.com 时,她的所有个人数据都将无法访问。如何让我的所有“子域”与主域共享相同的 localStorage?

6个回答

这就是我跨域使用它的方式...

  • 使用来自您父域的 iframe - 比如 parent.com
  • 然后在每个 child.com 域上,只需向您的 parent.com iframe 发送 postMessage
  • 您需要做的就是设置一个协议,用于解释如何解释您的 postMessage 消息以与 parent.com iframe 对话。

我希望它有帮助:)

这是真正的答案,而不是核对的答案。我自己已经完成了这项工作,但也使用 postMessage 创建了一个方便的回调包装器。
2021-03-13 02:04:33
请注意,这仅在未禁用第三方 cookie 时才有可能:stackoverflow.com/a/44097269/4311428
2021-03-24 02:04:33
Apple 更新了 Safari 7+ 在桌面和移动设备上的默认设置,以阻止 3rd 方数据。该选项现在称为“阻止 cookie 和其他网站数据”,它指的是像 localstorage 这样现在完全被域隔离的东西。此方法在 Safari 中不起作用
2021-03-27 02:04:33
这是一篇很好的文章,其中包含一些解释此方法的示例代码:jcubic.wordpress.com/2014/06/20/cross-domain-localstorage
2021-04-01 02:04:33
@Max @Aranganathan 它仍然适用于原始问题 - site.com/www.site.com只要子域在同一个父域上
2021-04-01 02:04:33

如果您仅针对这个特定问题使用 iframe 和 postMessage 解决方案,我认为将数据存储在无子域的 cookie 中可能会减少工作量(代码和计算),如果还没有在加载时的 localStorage 中,从 cookie 中获取它

优点:

  • 不需要额外的 iframe 和 postMessage 设置。

缺点:

  • 将使数据在所有子域(不仅仅是 www)中可用,因此如果您不信任所有子域,它可能对您不起作用。
  • 将在每次请求时将数据发送到服务器。不是很好,但根据您的情况,可能仍然比 iframe/postMessage 解决方案少。
  • 如果您这样做,为什么不直接使用 cookie?取决于你的上下文。
  • 4K 最大 cookie 大小,域的所有 cookie 总数(感谢 Blake 在评论中指出这一点)

不过,我同意其他评论者的意见,这似乎应该是 localStorage 的一个可指定选项,因此不需要解决方法。

其他缺点: - cookie 更有可能被广告拦截器阻止 - cookie 旨在用于在服务器和客户端之间共享小数据,如果服务器不使用您存储在 cookie 中的数据,则这是误用
2021-03-14 02:04:33
此外,正如我通过艰难的方式了解到的,4k 限制是针对单个域的所有 cookie 大小的总和,而不是针对每个 cookie。
2021-03-21 02:04:33
另一个缺点:在 Safari 和 Brave 等浏览器上,从前端设置的 cookie 的最长生命周期为 7 天。
2021-04-03 02:04:33
缺点:4k 最大 cookie 大小
2021-04-11 02:04:33

我建议将 site.com 重定向到 www.site.com 以保持一致性并避免此类问题。

此外,考虑使用跨浏览器解决方案,如PersistJS,它可以使用每个浏览器的本机存储。

是的,存储通常取决于域,包括子域。这就是我建议重定向的原因。您不一定需要管理员访问权限,只需在文档根目录中使用 .htaccess 规则即可
2021-03-21 02:04:33
我没有对服务器的管理员访问权限来执行此类重定向。该库是否允许我在 www 和非 www 之间共享持久数据?在做了一些阅读之后,似乎几乎所有浏览器的存储机制都不允许这样做。不管是cookies还是localStorage,我们都会遇到这个问题……
2021-03-24 02:04:33
@JoJo 有多种重定向方式,例如通过发送 header Location,或通过<meta>HTML 标签,甚至通过 JS 发送window.location
2021-04-05 02:04:33
这只是在逃避答案。将 Mayank 的答案视为正确。
2021-04-07 02:04:33
+1 @avoiding,另外这与其他情况无关 - 比如我在这里的那个 lang1.domain.com - lang2.domain.com
2021-04-11 02:04:33

在主域中设置为 cookie -

document.cookie = "key=value;domain=.mydomain.com"

然后从任何主域或子域中获取数据并将其设置在 localStorage 上

然后,所有的 post 请求都会被 CSRF 攻击打开。
2021-04-08 02:04:33

这是如何:

[ 2020 年 11 月更新: 此解决方案依赖于能够设置document.domain. 不幸的是,现在已经弃用了这样做的能力。]

为了在给定超级域(例如 example.com)的子域之间共享,您可以在这种情况下使用一种技术。它可以应用到localStorageIndexedDBSharedWorkerBroadcastChannel,等等,所有这些都提供相同来源的网页之间共享的功能,但由于某种原因不尊重任何修改document.domain,将让他们直接使用一个超级原籍。

(1) 为数据选择一个“主”域:即https://example.comhttps://www.example.com将保存您的 localStorage 数据。假设您选择https://example.com

(2) 通常为所选域的页面使用 localStorage。

(3) 在所有https://www.example.com页面(其他域)上,使用 javascript 设置document.domain = "example.com";. 然后还创建一个 hidden <iframe>,并将其导航到所选https://example.com上的某个页面哪个页面无关紧要,只要您可以在那里插入一小段 javascript。如果您重新创建站点,只需为此专门创建一个空页面。如果您正在编写扩展程序或 Greasemonkey 样式的用户脚本,因此对example.com上的页面没有任何控制权服务器,只需选择您能找到的最轻量级的页面并将您的脚本插入其中。某种“未找到”页面可能没问题)。

(4) 隐藏的 iframe 页面上的脚本只需要 (a) 设置document.domain = "example.com";,和 (b) 完成后通知父窗口。之后,父窗口可以不受限制地访问 iframe 窗口及其所有对象!所以最小的 iframe 页面是这样的:

<!doctype html>
<html>
<head>
  <script>
    document.domain = "example.com";
    window.parent.iframeReady();  // function defined & called on parent window
  </script>
</head>
<body></body>
</html>

如果编写用户脚本,您可能不想将外部可访问的函数添加iframeReady()到您的unsafeWindow,因此通知主窗口用户脚本的更好方法可能是使用自定义事件:

    window.parent.dispatchEvent(new CustomEvent("iframeReady"));

您可以通过将自定义“iframeReady”事件的侦听器添加到主页面的窗口来检测。

(注意:即使 iframe 的域已经是example.com,您也需要设置 document.domain = "example.com" :为 document.domain 分配一个值隐式地将源的端口设置为 null,并且两个端口都必须与 iframe 匹配及其父级被视为同源。请参阅此处的注释:https : //developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Changing_origin

(5)一旦隐藏的iframe已通知它的父窗口,它已经准备好,在父窗口脚本可以直接使用iframe.contentWindow.localStorageiframe.contentWindow.indexedDBiframe.contentWindow.BroadcastChanneliframe.contentWindow.SharedWorker而不是window.localStoragewindow.indexedDB等等......所有这些对象将范围限定于选择https://开头example.com来源 - 因此他们将为您的所有页面拥有相同的共享来源!

这项技术最尴尬的部分是您必须等待 iframe 加载才能继续。因此,例如,您不能在 DOMContentLoaded 处理程序中轻松地开始使用 localStorage。此外,您可能想要添加一些错误处理来检测隐藏的 iframe 是否无法正确加载。

显然,您还应该确保在页面的生命周期内不会删除或导航隐藏的 iframe... OTOH 我不知道这样做的结果是什么,但很可能会发生不好的事情。

并且,需要注意的是:document.domain可以使用标头阻止设置/更改Feature-Policy,在这种情况下,该技术将无法如所述使用。


然而,这种技术有一个明显更复杂的概括,它不能被 阻止Feature-Policy,并且还允许完全不相关的域共享数据、通信和共享工作器(即不仅仅是公共超级域的子域)。@Mayank Jain 已经在他们的回答中描述了它,即:

一般的想法是,就像上面一样,您创建一个隐藏的 iframe 来提供正确的访问来源;但不是直接获取 iframe 窗口的属性,而是使用 iframe 内的脚本来完成所有工作,并且仅使用postMessage()在 iframe 和主窗口之间进行通信addEventListener("message",...)

这是有效的,因为postMessage()甚至可以在不同来源的窗口之间使用。但它也更加复杂,因为您必须通过在 iframe 和主窗口之间创建的某种消息传递基础结构传递所有内容,而不是直接在主窗口的代码中使用 localStorage、IndexedDB 等 API。