前言
最近在学习浏览器知识的时候,讲到了浏览器之间的渲染进程共用的问题。其中 opener 能被引用到的两个页面,会在同一个渲染进程中。而这两个页面,可以称为:浏览上下文组。但在测试的时候,反倒是发现了一个opener 注意的问题,原因虽是“人祸”,但也要小心!基于此做下记录,给大家做个提醒。
如何使用
1.window.open 方法打开。
2.a 链接点击打开。
这里我们看第二种方法测试,首先确保 a.html 和 b.html 都在同一站点。
题外话:同一站点,它们都会有引用关系,只不过跨域也不能直接操作之前的页面,但跨域仍然可以拿到global,所以引用关系还是在的。
我们接着说:点击 a.html 链接跳转到 b.html ,此时b里面可以访问到a里面的整个window对象,是可以引用到的。
a.html:
<html>
<head><title>A</title>
</head>
<body><a href="./b.html" target="_blank">前往b页面</a>
</body>
</html>
b.html:
<html>
<head><title>B</title>
</head>
<body>我是b页面
</body><script> console.log(window.opener);//指向A页面window.opener.document.body.style.display = 'none' </script>
</html>
在 chrome 浏览器中,以上代码b页面里,opener 打印出来的应该是 null !
为什么呢?按理来说应该是跟我们前面的猜想一样啊!
原来chrome 88 之后更新了安全策略,默认 a 链接的 rel=‘noopener’,在这之前都是 rel=‘opener’
好的,这是个好消息。按理来说,我们就不用提防这个问题了对吧?浏览器帮我们做到了。
问题复现
当我在检查某个页面的时候,看到了如下代码,陷入了沉思,跟我一起来看下吧。
还是跟之前一样的环境,这里唯一的不同在于,写代码的时候,有人不小心写错了 a.html 的 target 单词a.html:
<html>
<head><title>A</title>
</head>
<body><a href="./b.html" target="_black">前往b页面</a>--这里的单词被人拼错了
</body>
</html>
b.html:
<html>
<head><title>B</title>
</head>
<body>我是b页面
</body><script> console.log(window.opener);//指向A页面window.opener.document.body.style.display = 'none' </script>
</html>
这就很有意思了,按理来说写错了代码,那么 target 就不会生效了?试着跑一下代码看看?a页面还是被消失了!而且 b 可以打印出 a 的 window !说明这里存在的安全问题!
虽然 target 设置的不是 _blank 但还是会生效,target 属性只要有值,就会默认:_blank 行为!打开的链接仍然会以新窗口打开。
隐患在于:
虽然 chrome88 以后为了安全,默认了 a 标签的 rel=“noopener” ,相当于 target 为 _blank 状态下的 a 标签 opener 为 null。而没有为其他的值也进行设置!这就会造成,如果开发者不小心设置为别的值(例如前面“人祸”打错字),依旧可以新窗口打开! opener 还能引用到之前的页面 , 如果某些开发者只依赖浏览器的默认安全策略,那么就会遭殃!
解决方案
强烈建议对所有 a 标签设置 rel=“noopener norefferrer” 加强明确属性,以杜绝此类问题发生!
其中注意:window.open 默认也会携带opener和 noreferrer 它有第三个参数可以把它们进行隐藏。
强烈建议对所有 a 标签设置 rel=“noopener norefferrer” 加强明确属性,以杜绝此类问题发生!
API介绍
关于前面这个问题,MDN上面也有专门的介绍:
返回打开当前窗口的那个窗口的引用,例如:在window A中打开了window B,B.opener 返回 A.
关于 opener 属性的解读,相信之前大家都有了解过。这里我们直接看MDN上的介绍,给不清楚的同学过一遍。