由a标签rel=_noopener noreferrer_属性引发对浏览器进程的思考

起因

相信大家对 eslint 一类的代码规范化工具肯定不会陌生了吧。现在的前端开发环境一般都是多人开发的模式,为了规范大家的编码规范,开发环境肯定会加入 eslint。我们开发时新建标签页打开一个链接,会用到 <a target="_blank"> 的语法,然而,使用 ESLint (react/jsx-no-target-blank ) rule时,会警告要加上 “rel="noreferrer noopener"”

由a标签rel=_noopener noreferrer_属性引发对浏览器进程的思考_第1张图片

这个时候需要给a标签加个属性 target="_blank" rel="noopener noreferrer" , 加 target="_blank" 的作用是新建标签页打开链接,那么 rel="noopener noreferrer" 是什么作用呢?

如果不加会造成什么影响?

使用 a 标签并设置 target="_blank" 打开一个新页面时,在很多浏览器(包括旧版本的Chrome、Firefox、Safari、Edge 等主流浏览器)中,新页面都会与原页面共享进程。这意味着在一些浏览器中这两个页面会共享相同的资源,包括 cookies、缓存、本地存储等。这种行为虽然可以提高性能和节省内存,但会造成很多不良风险:

  1. 新页面对原页面会造成一个安全漏洞,新的页面可以通过window.opener 访问原页面的窗口对象window。甚至新页面可以使用 window.opener.location = newURL将我们的原页面导航至不同的网址。就这样可以控制前一个页面,事情就是这么的可怕。而且不管它是否跨域了,都是可以的。

  2. 如果新页面正在执行开销极大的 JavaScript,原页面性能可能会受影响,新页面崩溃,也会使得共享进程中的其他页面崩溃。

  3. 如果在新页面中存在恶意代码,攻击者可以利用 window.openerwindow.postMessage 方法来访问原始页面并窃取敏感数据。

如何避免风险?

为了避免这些安全漏洞的发生,使用<a>标签打开新页面时,建议添加 rel="noopener noreferrer" 属性。

rel="noopener noreferrer" 属性的作用是告诉浏览器在打开新页面时采取一些安全措施,以防止新页面利用原页面的窗口对象执行恶意脚本,来防止钓鱼网站,提高页面安全性。具体来说:

  • rel="noopener": 防止新页面通过 window.opener 访问原页面的窗口对象,避免潜在的恶意行为。

  • rel="noreferrer": 防止新页面将来源地址发送给目标页面,避免潜在的隐私泄漏。

window.open(url, name)

事实上,除了使用 a 标签打开新页面时,有可能引起安全漏洞外,使用 window.open() 也会让新窗口继承了父窗口的 window.opener 属性,因此同样可能会导致一些安全问题。如何解决呢?

  1. 设置 window.opener 属性为 null:在新页面中,将 window.opener 属性设置为null,这样新页面就无法通过该属性访问原始页面的window对象。

const newWindow = window.open(url);
newWindow.opener = null;
  1. 使用 noopener 属性:在使用 window.open() 方法打开新页面时,可以添加 noopener 属性来告诉浏览器不要在新页面中引用原始页面,以避免新页面访问原始页面的window对象。

window.open(url, '_blank', 'noopener');
  1. 使用 noreferrer 属性:在 window.open() 方法中添加 noreferrer 属性,以告诉浏览器不要向新窗口发送任何来源信息,以避免泄露敏感信息。

window.open(url, '_blank', 'noreferrer');
  1. 转为 a 标签,利用 rel="noopener noreferrer" 属性。

浏览器层做出的策略

根据前面内容我们知道,这种安全漏洞是在某一些旧版本的浏览器中,各个厂家浏览器也都在为安全漏洞作出了方案来避免。比如:

  1. 从 Chromium 88 版开始,默认情况下,带有 target="_blank" 的锚点会自动获得 noopener行为。rel="noopener" 的显式规范有助于保护旧版浏览器(包括 Edge Legacy 和 Internet Explorer)的用户。

  2. 由a标签rel=_noopener noreferrer_属性引发对浏览器进程的思考_第2张图片

来源于:https://developer.chrome.com/zh/docs/lighthouse/best-practices/external-anchors-use-rel-noopener/

  1. Chrome 63是于2017年12月发布版本,引入了 Site Isolation(站点隔离) 策略,将每个站点隔离在单独的进程中运行,以提高安全性并防止恶意站点利用漏洞攻击其他站点。

那么什么是Site Isolation(站点隔离)呢?

引入站点隔离前的历史进程模型

在引入站点隔离之前,Chromium最初支持了一些进程模型,包括:

  1. Single Process Mode(单进程模式): 浏览器所有的页面都在同一个进程中运行,该进程扮演着浏览器和渲染器的双重角色。

  2. Process-per-Site Model(基于站点的进程模式): 每个站点拥有自己的渲染进程,将同一个站点(比如 Google.com)的所有页面都放在同一个渲染进程里,不同站点则使用不同的渲染进程。在这种模式下,可以提高性能,因为在同一个进程里的页面可以共享内存,同时可以减少资源的消耗,因为进程的数量相对较少。但是这种方式也存在一些安全隐患,比如一个站点内的恶意代码可能会影响到其他页面,因为它们在同一个进程中运行。

  3. Process-per-tab Model(基于标签页的进程模式):每个标签页都有自己的渲染进程,这些进程只渲染与该标签页相关的页面。用户在同一标签页中打开了多个页面,它们会在同一个进程中运行。但是,如果这些标签页被打开时使用了相同的进程标识符(如window.open()),那么它们可能会被分配到同一个进程中。就会发生上文讲到的安全漏洞问题。

  4. Process-per-site-instance Model(基于站点实例的进程模式): 每个站点实例都有自己的渲染进程,这些进程只渲染与该站点实例相关的页面。在这种模式下,如果用户打开了同一站点的多个实例,它们会在不同的进程中运行。

以上模式的主要区别在于如何为页面分配进程,这些模式也存在一些共同的问题,如安全性和性能问题。为了解决这些问题,Chromium引入了Site Isolation(站点隔离) 策略。

Site Isolation(站点隔离)策略

Sit e Isolation 模型是 Chrome 最新的进程管理模型,它通过使用独立的进程来隔离每个网站,从而提高了安全性。在 Site Isolation 模型中,每个不同的网站都在其自己的进程中运行,这样即使同一进程中的多个选项卡被攻击,攻击者也无法跨越进程边界访问其他网站或系统资源。它主要优势包括:

  1. 提高安全性: 站点隔离可以有效降低恶意网站攻击浏览器的风险,防止恶意网站窃取用户信息或在用户电脑上执行恶意代码。

  2. 提高稳定性: 每个网站都有自己的进程,一个网站崩溃不会影响其他网站的运行,从而提高浏览器整体的稳定性。

  3. 提高性能: 站点隔离可以利用现代多核 CPU 的性能优势,将负载分散到多个进程中,从而提高浏览器的整体性能。

  4. 提高隐私保护: 站点隔离可以防止同一域名下的不同页面之间共享数据,从而提高隐私保护。

但是这种方式也会增加浏览器的内存和CPU使用率,因为需要为每个站点创建一个独立的进程。这可能会导致性能下降,尤其是在低端设备上。

总的来说,站点隔离是为了更加严格地保护用户安全而采用的策略。

Chrome 63以后,就默认采用站点隔离了。在 Chrome 67 中,站点隔离已被 99% 的 Windows、Mac、Linux 和 Chrome OS 用户启用。这意味着即使在恶意网页中发生 Spectre 攻击,其他网站的数据通常也不会被泄露。因此攻击者可用的数据会少得多。这显着降低了 Spectre 带来的威胁。

参考资料:

https://security.googleblog.com/2018/07/mitigating-spectre-with-site-isolation.html

https://chromium.googlesource.com/chromium/src/+/main/docs/process_model_and_site_isolation.md#Historical-Modes

https://www.cnblogs.com/minorf/p/12987230.html

你可能感兴趣的:(javascript,前端,开发语言,ecmascript)