html 在postmessage中指定多个targetOrigin URI

42fyovps  于 2023-06-04  发布在  其他
关注(0)|答案(3)|浏览(191)

Window.postMessage()有一个targetOrigin参数,可以设置为URI(以确保消息只到达特定的url)。当然,它也可以设置为*(不推荐),但是有没有一种方法可以指定多个URI?
目前,我只是为每个域发出一个postMessage()调用,但至少可以说,这似乎有点笨拙。

jckbn6z7

jckbn6z71#

很不幸你不能。您应该提供“*”或单个指定域。

h4cxqtbf

h4cxqtbf2#

您可以尝试发送多个时间,每个域一个:

targetWindow.postMessage(message, "https://domain1.com");
targetWindow.postMessage(message, "http://localhost");

不建议使用“*”,以防止安全漏洞。

  • 你也可以创建一个数组+循环 *
mwecs4sa

mwecs4sa3#

虽然Juanmabs22's answer应该 work™,但这也会在每个不匹配的来源上触发一个无法捕获的控制台错误消息,这对于那些希望自己的网站完全不产生错误消息的人来说可能不是最佳选择。
对于那些仍然想要安全通信通道的人(因此不想要不安全的通配符解决方案),有一个公认的麻烦的解决方案:
在发送敏感数据之前,您可以设置通过不安全的targetOrigin: "*"发起的握手协商。在第一条消息中,您将询问嵌入器的来源,然后,只有当该来源与您预期的来源匹配时,您才可以使用该来源启动安全通信。这意味着嵌入器必须公开它们的来源,但是它们可以使用MessageEvent#origin属性检查您的消息是否来自脚本的来源。
所以这会给予,
在embeddee.html(您的脚本)中:

async function initComm(allowedOrigins = []){
  const unsafe = new MessageChannel();
  parent.postMessage("negotiation", {
    targetOrigin: "*", // we're using the unsafe wildcard only for this request
    transfer: [unsafe.port1]
  });
  // In case we're talking to someone who doesn't know about our handshake
  const timeout = AbortSignal.timeout(100);
  const targetOrigin = await Promise.race([
    new Promise((res, rej) => timeout.onabort = (evt) => {
      unsafe.port2.close(); // clean
      rej(timeout.reason);
    }),
    // Wait for a response
    new Promise((res) => unsafe.port2.onmessage = ({data}) => res(data))
  ]);
  unsafe.port2.close();
  if (!allowedOrigins.includes(targetOrigin)) {
    throw new Error("Unknown origin: " + targetOrigin);
  }
  const safe = new MessageChannel();
  // Even if they lied, we're using the safe targetOrigin option
  parent.postMessage("begin", { targetOrigin, transfer: [safe.port1] });
  return safe.port2;
}
const safePort = await initComm(["https://embedder-1.com", "https://another-origin.com"]);
// now you can use this MessageChannel to send sensitive data
safePort.postMessage("Here is a secret");

在嵌入器侧:

onmessage = ({origin, data, ports}) => {
  if (origin === YOUR_SCRIPT_ORIGIN) { // only if they recognize you
    switch(data) {
      case "negotiation":
      ports[0].postMessage(window.origin);
      break;
    case "begin":
      beginComm(ports[0]);
      break;
    }
  }
}
function beginComm(safePort) {
  safePort.onmessage = ({data}) => {
    // Now they can handle your messages
    console.log("Safely received a new message", data);
  };
}

不幸的是,StackSnippet的null origined iframe是一个非常糟糕的例子,所以here is an outsourced JSFiddle

相关问题