🎄

ENCA 11日目: SharedArrayBuffer のオプショナル化

2024/12/11に公開

SharedArrayBuffer のオプショナル化

ES2017 に満を持して入った SharedArrayBuffer でしたが、その後 CPU の投機的実行を悪用した Spectre 脆弱性が発見されてしまい、攻撃を緩和するために高精度に時間が測定できる performance.now() の精度が落とされ、SharedArrayBuffer が無効化されてしまうこととなりました。

詳しくは jxck さんのブログ記事を参考にしてください。

https://blog.jxck.io/entries/2020-05-22/site-isolation.html

さて言語仕様側でもこの対応が必要となり、グローバル変数から SharedArrayBuffer を取り除いて良いこととする変更が承認されました。

https://github.com/tc39/ecma262/pull/1903

クロスオリジン分離で SharedArrayBuffer を有効化する

ブラウザで SharedArrayBuffer を有効化するには HTTPS で配信された安全なコンテキストであることと、Cross-Origin-Opener-Policy (COOP) と Cross-Origin-Embedder-Policy (COEP) フィールドを使ってクロスオリジン分離する必要があります。

https://web.dev/articles/coop-coep?hl=ja

なお余談ですが、クロスオリジン分離になっていなくても SharedArrayBuffer コンストラクタ自体をグローバル変数から取り除く必要はなく、postMessage などでやり取りする箇所でせき止めれば十分です。互換性の観点からグローバル変数から取り除いたままになっていますが、実はクロスオリジン分離でなくても WebAssembly.Memory を使ってコンストラクタを取得できます(役には立ちませんが)。

const memory = new WebAssembly.Memory({ shared: true, initial: 0, maximum: 0 });
const SharedArrayBuffer = memory.buffer.constructor;

これについては HTML Standard にも書かれています。

If agent's agent cluster's cross-origin isolation mode is "none", then:

  1. Let global be realm's global object.
  2. Let status be ! global.[[Delete]]("SharedArrayBuffer").
  3. Assert: status is true.

Note: This is done for compatibility with web content and there is some hope that this can be removed in the future. Web developers can still get at the constructor through new WebAssembly.Memory({ shared:true, initial:0, maximum:0 }).buffer.constructor.

https://html.spec.whatwg.org/multipage/webappapis.html#creating-a-new-javascript-realm

Discussion