乐趣区

关于前端:windowname和postMessage安全问题比较

一、概念

1. window.name

  1. 在窗口还没被敞开之前,窗口载入的所有页面都共享同一个 window.name。
    这个窗口可了解为 chrome 的一个 tab 标签页面,在该页面中跳转关上另一个页面后,这些页面都共享同一个 window.name。
  2. 每个页面都能读写 window.name。
    这个可能就是平安问题的起源。
  3. 能够存储不超过 2M 的数据。
    大小没测试过,MDN 上没阐明,但有些文章有提到。

可参考:
https://developer.mozilla.org/zh-CN/docs/Web/API/Window/name
https://www.jianshu.com/p/43ff69d076e3

2. postMessage

  1. 能够平安地实现跨源通信。
  2. 提供了一种受控机制来躲避此限度,只有正确的应用,这种办法就很平安。

语法:
otherWindow.postMessage(message, targetOrigin, [transfer]);

事件:
window.addEventListener("message", receiveMessage, false);
message 的属性有:data, origin, source

详情可参考:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage

二、平安问题比拟

简称:
攻击者页面:A
被攻击者页面:B

1. window.name

  1. 可通过在 A 中嵌入 B,实现在 A 获取 B 的 window.name 的数据
  2. 如果 B 中存在 eval 执行 window.name 的代码,则存在 xss 平安问题,因为在 1 的根底上,A 可批改 window.name 的数据,从而导致 B 呈现 xss 问题

2. demo 验证:

验证观点 1

A:http://localhost:3000/window.name.html
B:http://localhost:3001/window.name.html
成果如下图:

代码如下:

// A 页面:<head>
    <meta charset="utf-8">
    <title>window.name</title>
</head>
<body>
    <script>
        function iframeOnload() {var iframe = document.getElementById('iframe');
            iframe.onload = function () {console.log('攻击者页面 log:被攻击者页面的数据已拿到:', iframe.contentWindow.name);
            }
            iframe.src = 'http://localhost:3000/xx.html'
        }
    </script>
    <iframe id="iframe" src="http://localhost:3001/window.name.html" onload="iframeOnload()"></iframe>
</body>

// B 页面:<head>
    <meta charset="utf-8">
    <title>window.name</title>
</head>
<body>
    <script>
        window.name = '这是重要信息!!!'
        console.log('被攻击者页面 log:', window.name)
    </script>
</body>

验证观点 2

A:http://localhost:3000/window.name.html
B:http://localhost:3001/window.name.html
成果如下图:
先关上 A 页面,1 秒钟后,跳转到 B 页面,并执行 alert 代码

代码如下:

// A 页面
<head>
    <meta charset="utf-8">
    <title>window.name</title>
</head>
<body>
    <script>
        window.name = 'alert(/xss/)'
        console.log(window.name)
        setTimeout(() => {location.href = 'http://localhost:3001/window.name.html'}, 1000)
    </script>
</body>

// B 页面
<head>
    <meta charset="utf-8">
    <title>window.name</title>
</head>
<body>
    <script>
        console.log('被攻击者页面 log:', window.name)
        eval(window.name)
    </script>
</body>

3. postMessage

不存在 window.name 的第一个问题,因为 postMessage 要指定源 targetOrigin,只有不是该源的,都收不到音讯。同时,在接管音讯的时候,也能够指定起源 origin,如果起源不对,则可不读取音讯。

解决跨域问题,当初根本用 postMessage。

但 postMessage 也存在有余,比方只能指定特定的源,绝对失常的 xhr 申请,减少代码量。
所以如果能开 cors,则根本是完满的跨域解决方案。

MDN 上平安问题的倡议:

如果您不心愿从其余网站接管 message,请不要为 message 事件增加任何事件侦听器。这是一个齐全十拿九稳的形式来防止平安问题。
如果您的确心愿从其余网站接管 message,请始终应用 origin 和 source 属性验证发件人的身份。任何窗口(包含例如 http://evil.example.com)都能够向任何其余窗口发送音讯,并且您不能保障未知发件人不会发送歹意音讯。然而,验证身份后,您依然应该始终验证接管到的音讯的语法。否则,您信赖只发送受信赖邮件的网站中的安全漏洞可能会在您的网站中关上跨网站脚本破绽。
当您应用 postMessage 将数据发送到其余窗口时,始终指定准确的指标 origin,而不是 *。歹意网站能够在您不知情的状况下更改窗口的地位,因而它能够拦挡应用 postMessage 发送的数据。

退出移动版