可以跨子域共享HTML5数据库和localStorage吗?

时间:2010-11-14 14:01:27

标签: database html5 dns subdomain local-storage

我正在尝试使用Safari在子域之间共享数据。我想使用HTML5数据库(特别是 localStorage ,因为我的数据只是键值对)。但是,似乎无法从 sub.domain.com 访问存储到 domain.com 的数据(反之亦然)。在这种情况下,有没有办法共享一个数据库?

4 个答案:

答案 0 :(得分:12)

2016年更新

Zendesk的library为我工作。

示例:

<强>集线器

// Config s.t. subdomains can get, but only the root domain can set and del
CrossStorageHub.init([
  {origin: /\.example.com$/,            allow: ['get']},
  {origin: /:\/\/(www\.)?example.com$/, allow: ['get', 'set', 'del']}
]);

请注意$以匹配字符串的结尾。上例中的正则表达式将匹配valid.example.com等起源,但不匹配invalid.example.com.malicious.com

<强>客户端

var storage = new CrossStorageClient('https://store.example.com/hub.html');

storage.onConnect().then(function() {
  return storage.set('newKey', 'foobar');
}).then(function() {
  return storage.get('existingKey', 'newKey');
}).then(function(res) {
  console.log(res.length); // 2
}).catch(function(err) {
  // Handle error
});

检查https://stackoverflow.com/a/39788742/5064633

答案 1 :(得分:9)

有一种简单的方法可以使用跨域名称,只需创建一个简单的页面,将其作为代理 iframe 包含在您尝试访问的域中,将 PostMessage 发送到那个iframe和内部iframe你做了LocalStorage数据库操作。这是article that do this with lcoalStorage的链接。这里是demo that send message to different page in subdomain检查源代码,它使用iframe和PostMessage。

答案 2 :(得分:4)

默认情况下,Google Chrome会阻止来自其他域中iFrame的localStoage访问,除非启用了第三方Cookie,因此iPhone上的Safari也是如此...唯一的解决方案似乎是打开其他域上的父域,然后发送到通过window.postMessage给孩子,但在手机上看起来很丑陋......

答案 3 :(得分:0)

是。这是这样的:

要在给定超域的子域之间共享(例如foo.example.com与bar.example.com与example.com),可以在这种情况下使用一种技术。它可以应用于localStorageIndexedDBSharedWorkerBroadcastChannel等,所有这些元素在同源页面之间提供共享功能,但是由于某些原因不尊重对document.domain的任何修改,这些修改将允许他们直接使用超域作为其起源。

(1)选取一个“主”域作为数据所属的域:即 https://foo.example.com https://bar.example.com https://example.com 将保存您的localStorage数据。假设您选择https://example.com

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

(3)在所有其他 https://*.example.com 页面( other 域)上,使用javascript设置document.domain = "example.com";(始终超域)。然后还创建一个隐藏的<iframe>,并将其导航到所选 https://example.com 域上的 some 页面( < em>什么页面,只要您可以在其中插入一小段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分配一个值会隐式设置来源的 port 设置为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我不知道这样做的结果,但是很可能会发生坏事。 / p>

而且,需要警告:可以使用document.domain标头阻止设置/更改Feature-Policy,在这种情况下,该技术将无法按所述使用。


但是,这种技术的概括要复杂得多,Feature-Policy不能阻止它,并且允许完全不相关的域共享数据,通信和共享的工作器< / strong>(即不只是普通超级域的子域)。 @jcubic已经在回答中对此进行了描述,即:

总体思路是,如上所述,您创建了一个隐藏的iframe以提供正确的访问源;但是,您不仅可以直接获取iframe窗口的属性,还可以在iframe中使用脚本来完成所有工作,并且仅使用postMessage()addEventListener("message",...)在iframe和主窗口之间进行通信。 / p>

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