rel=noopener是什么

问题的出现

昨晚上用ESLint检查代码时,出现了这样一行错误:

Using target=”_blank” without rel=”noopener noreferrer” is a security risk: see https://mathiasbynens.github.io/rel-noopener react/jsx-no-target-blank

当然加上rel="noopener noreferrer"之后报错就没有了,可问题是:what’s this?

关于rel

rel是relationship的缩写,用于指定当前文档与href链接的文档的关系(顺便一说,rev属性已在HTML5中废弃)。MDN中如此描述:

rel

对于锚点来说,rel具有href的属性, 该属性指定了目标对象到链接对象的关系。该值是空格分隔的列表关系值。 该值和语义可能将会被一些权威文档编者赋予不同的含义。 在默认的情况下,如果没有其它定义,是无效的,只有在 href 存在的情况下,使用该属性。

并且在target 属性后面写到:

注意:使用target时,考虑添加 rel=”noopener norefferrer” 以防止针对 window.opener API 的恶意行为。

由此看来,写上这条属性的好处首先是让链接的语义更加明确,语义明确后,自然是搜索引擎友好,然后还可以提升网页的安全性。

问题究竟是什么

关于window.opener,MDN里有这么一句:

备注

如果当前窗口是由另一个窗口打开的, window.opener保留了那个窗口的引用. 如果当前窗口不是由其他窗口打开的, 则该属性返回 null.

我想问题大概就是在这里吧,链接到信任的站点自然可以灵活地使用,可是一旦链接到钓鱼网站,这个网站可以做什么你总是难以预料。但总的来说,这种行为的潜在风险是远远大于好处的。

接下来该怎么做

对于rel="noopener"这个属性,在Chrome 49+、Opera 36+中可以将window.opener设置为null,但如果浏览器是比较老的版本,实际上要使用rel="noopener norefferrer"去完整覆盖,将HTTP头部Referer属性也禁用掉。

其实我个人还是偏向于听从最开始那篇文章里的建议:

Don’t use target=_blank (or any other target that opens a new navigation context), especially for links in user-generated content, unless you have a good reason to.

所以说,尤其是网站用来对外提供给用户使用的情况下,请不要低估这个问题,更没有理由去忽视这个问题。