1. はじめに
この節は非規範的です。
ストレージは通常、ユーザーのセキュリティとプライバシーを保護するためにオリジンごとに分割されます。これは適切な デフォルトですが、非常に大容量で、非常に普及し、一般に配布される限られた種類の リソース — AI モデル、WebAssembly モジュール、JavaScript ライブラリ、ゲームエンジン、大容量 Web フォント — には適していません。これらは、どのサイトが要求してもバイト単位で同一のファイルです。互いに無関係な 2 つのオリジンが 同じ 8 GB のモデルに依存する場合、オリジン分割ストレージではユーザーが そのモデルを 2 回ダウンロードして保持することを強制され、ユーザーの帯域幅、ストレージ、 バッテリー、そしてネットワーク全体を浪費します。
オリジン間ストレージ(COS)は、URL ではなく暗号学的ハッシュをキーとするコンテンツアドレス可能なキャッシュであり、ユーザーエージェントが、その利用をオプトインした オリジン間で、このようなリソースの単一の保存済みコピーを共有できるようにします。COS へのリソースの保存は、保存元オリジンによる 明示的なオプトイン操作であり、ユーザーエージェントは、本来そのリソースの読み取りを許可されるオリジンに対しても、 リソースの存在確認を控えることができます。§ 7 プライバシーおよび セキュリティに関する考慮事項を参照してください。
この仕様のエントリポイントは、requestFileHandle()
メソッドであり、crossOriginStorageを介して公開されます。
const hash= { algorithm: 'SHA-256' , value: '8f434346648f6b96df89dda901c5176b10a6d83961dd3c1ac88b59b2dc327aa4' , }; try { const handle= await navigator. crossOriginStorage. requestFileHandle( hash); const file= await handle. getFile(); // ファイルを使用して何らかの処理を行う。 } catch ( err) { if ( err. name=== 'NotFoundError' ) { // オリジン間ストレージ内に(開示可能な状態で)存在しないため、代わりにネットワークから取得する。 } }
この仕様は、FileSystemFileHandle、
FileSystemWritableFileStream、
およびファイルシステム標準 [FS]
の関連インフラストラクチャを再利用しますが、単一オリジンの非公開またはユーザーに可視なファイルシステムではなく、
専用のオリジン間共有ファイルシステムに適用します。
この仕様は命令型 JavaScript API のみを定義します。関連する提案では、同じ基盤となるキャッシュを
他のホスト仕様に統合します — HTML の crossoriginstorage 属性(
link
および
script)、
crossOriginStorage JavaScript import 属性、CSS の
cross-origin-storage() <request-url-modifier>、および
fetch() 用の crossOriginStorage RequestInit
オプションです — それぞれは各自のホスト仕様で定義されています。次を参照してください:
§ 8 他の仕様との統合。
2. 概念
2.1. ハッシュ
- アルゴリズム
-
[WEBCRYPTO]が認識するハッシュアルゴリズムの名前を表す文字列です。たとえば「
SHA-256」です。 - 値
-
アルゴリズムによって生成されたダイジェストを小文字の 16 進数で符号化した文字列です。 「
SHA-256」の場合、長さは 64 文字です。
algorithm
辞書メンバーは、その値空間が [WEBCRYPTO] のハッシュアルゴリズムが受け付ける名前の集合と完全に一致するにもかかわらず、HashAlgorithmIdentifierではなく、単純な
DOMStringとして型付けされています。HashAlgorithmIdentifier
は
(object or DOMString) であり、追加で object を受け付けます。このオブジェクトは [WEBCRYPTO] によって
Algorithm形式の
辞書へ正規化され、呼び出し元は必要なアルゴリズムに追加パラメーターを渡せます
(たとえば {name: "HMAC", hash: "SHA-256"})。ハッシュアルゴリズムはそのようなパラメーターを受け取らず、
アルゴリズムは単一の操作によって一度だけ消費されるのではなく、コンテンツアドレス可能な
キーの一部として保存、比較、ラウンドトリップされます。また、この仕様の
すべての例では単純な文字列が使用されています。ここで任意のオブジェクトを許可しても機能は増えず、
等価性とシリアル化を
不必要に複雑にするだけです。したがって、DOMString がこのフィールドにとって
より限定的で、より適切な型です。
2 つのCOS ハッシュ値は、それらのアルゴリズム 値がASCII 大文字小文字不区別で一致し、かつそれらの値が厳密に 等しい場合に、等しいとします。
注: 大文字小文字が規範的に制約されていないアルゴリズムとは異なり、 値はすでに規範的に 小文字であるため(上記参照)、その比較はASCII 大文字小文字不区別の比較ではなく、単純な 文字列比較です。
コンテンツアドレス可能な ストアとは、そのエントリが URL や名前ではなく、 COS ハッシュの等価性をキーとするものです。バイト列が同一で、同じハッシュアルゴリズムを使用する 2 つのファイルは、 保存したオリジンの数や取得元 URL の数に関係なく、同じエントリです。
2.2. COS エントリ
各ユーザーエージェントには単一のCOS レジストリがあり、これはCOS ハッシュ値から COS エントリの構造体へのマップであり、オリジン間ストレージを使用するすべてのオリジンによって共有されます。 COS エントリは、次の項目を持ちます。
- ハッシュ
- バイト列
-
null、またはバイト列であり、ハッシュのアルゴリズム によるダイジェストが、ハッシュの値と等しいもの。ライターが 検証と 保存を完了するまでは null。
- 状態
-
「
pending」または「written」のいずれか。エントリーは「pending」として開始し、 バイト列が最初に設定されたとき、ちょうど一度だけ「written」になる。 - 保留中のライター数
-
初期値が 0 の負でない整数であり、未完了のライター、すなわち作成要求を完了するによって返された
FileSystemFileHandleハンドルのうち、その終了書き込みが まだ確定していないものを数える。検証して保存するにおいて、失敗した書き込みを安全に クリーンアップできるかどうかを判断するためにのみ使用される。§ 3.3 ファイルの作成と書き込みを参照。 - オリジン
-
宣言された共有範囲。「
*」(任意のオリジン)、オリジン文字列のリスト (それらのオリジンのみ)、または null(同一サイトのオリジンのみ)のいずれか。最初のライターによって設定され、 アップグレード可能だが、ダウングレードは不可能。 - 保存元オリジン
-
このエントリーのバイト列の書き込みをそれぞれ少なくとも一度正常に完了したオリジンの集合。ページの読み込みをまたいで永続化され、 時間の経過とともに増加する。§ 5.2 退去で説明される場合を除き、減少することはない。保存元オリジンに含まれるオリジンは、 オリジンや、 エントリーのハッシュが公開ハッシュリスト (PHL)に掲載されているかどうかにかかわらず、
requestFileHandle()を介して常にそのエントリーのハンドルを取得できる。 § 3.4.1 元の保存者によるアクセスを参照。
ユーザーエージェントには、新しい並列キューを開始した結果である、関連付けられたオリジン間ストレージキューがあります。COS レジストリに対するすべての操作は、 このキューにエンキューされなければならず、それによって操作は エンキューされた 順序で実行され、互いに割り込むことがありません。
2.3. 公開ハッシュリスト
あるハッシュがオリジン間ストレージ内に存在することを確認する行為自体が、
ユーザーの閲覧履歴に関する情報を漏えいさせる可能性があります(§ 7.2 サイト間プロービングを参照)。これは、特にグローバルな
範囲を持つエントリに関するリスクです。オリジンがリストまたは null であるエントリは、
保存元オリジンの明示的な選択によってすでに開示範囲が限定されていますが、「*」は、エントリを
Web 上の任意のオリジンに公開する可能性があります。この特定のリスクを限定するため、「*」範囲のリソースは、
その保存元オリジン外のオリジンに対して、ハッシュが追加の独立したゲートを通過した場合にのみ
開示できます。このゲートは、ベンダー中立で実装定義のCOS ハッシュ
値の許可リストである公開ハッシュリスト
(PHL)への登録です。ハッシュは、
k-匿名性方式の人気度基準を満たした場合にのみ公開ハッシュリストに登録されます。たとえば、一定数以上の独立した
オリジンに、バイト単位で同一のものが存在する場合です。これにより、共有キャッシュ内にそのハッシュが存在することを確認しても、
個々のユーザーに関する情報にはなりません。
COS ハッシュ hashは、 hashがユーザーエージェントの現在の公開ハッシュリストのスナップショット内のエントリと 等しい場合に、公開ハッシュ リストに含まれるものとします。
Public Hash List の取得プロトコル、 更新頻度、データ形式、人気閾値、およびガバナンスは、この仕様の付属成果物として詳細に設計されており、 [URL] Standard のパブリックサフィックスリストが規範的な文ではなく付属データファイルであるのと同じ趣旨で、 このリポジトリの Public Hash List explainer を参照してください。この設計では、 Public Suffix List のベンダー横断的なローリングリリースの前例をモデルとして WHATWG によるガバナンスを提案し、 独立して裏付けられた普遍性を基準とする登録基準を採用しています。これは、上記で説明した k-anonymity スタイルの基準を 具体化したものであり、ユーザーエージェントがクエリごとに繰り返し確認するものではなく、ハッシュが登録される方法の一部として 一度だけオフラインで適用されます。この提案以外では、これらはまだ確立されていません。リスト自体の初期の非規範的なコードプロトタイプは、 このリポジトリの public-hash-list/implementation/ で維持されています — 実用的な 暫定的な配置場所です。専用のベンダー横断的なリポジトリは、PHL explainer で説明されているガバナンス目標として残されています。 この仕様は、特定の取得メカニズムやガバナンスモデルではなく、ハッシュが PHL 上にある かどうかだけに依存するため、その設計が どのように発展しても正しい状態を維持します。
3.
CrossOriginStorageManager
インターフェイス
[Exposed =(Window ,Worker ),SecureContext ]interface {CrossOriginStorageManager Promise <FileSystemFileHandle >requestFileHandle (CrossOriginStorageRequestFileHandleHash ,hash optional CrossOriginStorageRequestFileHandleOptions = {}); };options dictionary {CrossOriginStorageRequestFileHandleHash required DOMString ;value required DOMString ; };algorithm dictionary {CrossOriginStorageRequestFileHandleOptions boolean =create false ; (DOMString or sequence <DOMString >); };origins interface mixin { [NavigatorCrossOriginStorage SameObject ,SecureContext ]readonly attribute CrossOriginStorageManager crossOriginStorage ; };Navigator includes NavigatorCrossOriginStorage ;WorkerNavigator includes NavigatorCrossOriginStorage ;
各Navigator
およびWorkerNavigator
オブジェクトには、関連付けられたCrossOriginStorageManager
オブジェクトがあります。crossOriginStorage ゲッターの
手順は、thisに関連付けられたCrossOriginStorageManagerを返すことです。
各CrossOriginStorageManager
オブジェクトには、オブジェクトの作成時に
thisの関連設定オブジェクトのオリジンに設定される、関連付けられたオリジンがあります。
注: スクリプト自体に関する何らかの情報ではなく、関連設定オブジェクトからオリジンを取得することには、ワーカーについて明記する価値のある影響がある。
blob: URL から作成されたワーカーは、それを作成したコンテキストのオリジンを持つため、そのオリジンの
Cross-Origin Storage ビューを完全に共有する。すなわち、そのようなワーカーが書き込んだものは、その作成元ページが読み戻すことができ、
ページが保存したものは、ワーカーが読み取ることができる。blob: URL 自体は独自のオリジンではなく、
それを取り消しても、ワーカーがそのビューから切り離されることはない。これに対して、data: URL から
作成されたワーカーは、不透明なオリジンを持つ。この仕様は現在、
requestFileHandle()
が、呼び出し元のオリジンが不透明である場合に何を行うかを定義していない。
不透明なオリジンに関する COS リクエストを検証する際の規則が対象とするのは、
呼び出し元が
指定するオリジンであり、呼び出し元自身のオリジンではない。不透明なオリジンには、
保存
オリジンや同一
サイトの比較のキーとして使用できる安定した識別情報がないため、
それに付与できる意味のあるものは何もない。
3.1. requestFileHandle()
メソッド
- handle = await navigator . crossOriginStorage .
requestFileHandle(hash) -
hash によって識別されるファイルが Cross-Origin Storage に存在し、呼び出し元 オリジンに開示可能である場合、そのファイルのハンドルを返す。それ以外の場合、これは "
NotFoundError"DOMExceptionで拒否される。 "NotFoundError" は、ファイルが Cross-Origin Storage に物理的に存在しないことを証明するものではない。§ 7.3 可用性ゲーティングを参照。呼び出し元は これを「代わりにこれをネットワークから取得する」として扱うことができる。 - handle = await navigator . crossOriginStorage .
requestFileHandle(hash, {create: true }) -
hash によって識別されるファイルを Cross-Origin Storage に書き込むために使用できるハンドルを返し、まだエントリーが存在しない場合は新しいエントリーを作成する。デフォルトでは同一サイトのオリジンに制限される。 呼び出し元は、エントリーがすでに 存在していたかどうかにかかわらず、ハンドルの
createWritable()メソッドを介してファイルの完全な内容を書き込む必要がある。ユーザーエージェントはその時点で、書き込まれたバイト列のハッシュが hash になることを検証し、 そうでない場合は "DataError"DOMExceptionで拒否する。この要件により、 オリジンが作成リクエストを、hash がすでに存在していたかどうかを判定するオラクルとして使用することを防ぐ。 - handle = await navigator . crossOriginStorage .
requestFileHandle(hash, {create: true,origins: "*" }) -
上記と同様だが、さらに、書き込み後は hash に対するリクエストが § 7.3 可用性ゲーティングを通過する任意のオリジンにエントリーを開示可能にする。
- handle = await navigator . crossOriginStorage .
requestFileHandle(hash, {create: true,origins: ["https://a.example", "https://b.example"] }) -
上記と同様だが、開示を列挙されたオリジンのみに制限する(呼び出し元 オリジン、およびすでに保存オリジンに含まれる任意のオリジンに加えて)。
requestFileHandle(hash, options)
メソッドの
手順は次のとおりである:
-
result を新しい promise とする。
-
global を this の関連グローバルオブジェクトとする。
-
global に関連付けられた
Documentが存在する場合に、それが "cross-origin-storage" ポリシー制御機能の使用を許可されていない場合、次を行う:-
global を与えて、DOM 操作タスクソース上でグローバルタスクをキューに入れ、 result を "
NotAllowedError"DOMExceptionで 拒否する。 -
result を返す。
-
-
validationFailure を、hash および options を与えてCOS リクエストを検証する処理を実行した結果とする。
-
validationFailure が null でない場合:
-
global を与えて、DOM 操作タスクソース上でグローバルタスクをキューに入れ、 result を validationFailure で 拒否する。
-
result を返す。
-
-
次の手順を Cross-Origin Storage キューにエンキューする:
-
options["
create"] が true の場合:-
result、hash、options、global、および realm を与えて、作成リクエストを完了する処理を実行する。
-
-
それ以外の場合:
-
result、hash、origin、global、および realm を与えて、読み取りリクエストを完了する処理を実行する。
-
-
-
result を返す。
CrossOriginStorageRequestFileHandleHash
hash
および CrossOriginStorageRequestFileHandleOptions
options を与えて COS
リクエストを検証するには、null または TypeError
を返す:
-
hash["
algorithm"] が [WEBCRYPTO] によって認識されるハッシュアルゴリズム 名でない場合、新しいTypeErrorを返す。 -
hash["
value"] が、hash["algorithm"] が "SHA-256" と ASCII 大文字・小文字を区別しない 一致であるときに、正規 表現/^[0-9a-f]{64}$/と一致しない場合、新しいTypeErrorを返す。注: 将来のハッシュアルゴリズムでは、 異なる期待ダイジェスト長を定義できる。この 仕様が規範的に制約するのは "
SHA-256" のみであり、これは 例全体での 使用と一致する。 -
null を返す。
3.2. ファイルの読み取り
-
entry を、COS レジストリ内の、そのハッシュが hash と等しい COS エントリーが存在する場合はそのエントリーとし、それ以外の場合は null とする。
-
entry が null でなく、かつ entry の状態が "
pending" の場合:-
global を与えて、DOM 操作タスクソース上にグローバルタスクをキューに入れ、 result を "
NotAllowedError"DOMExceptionで 拒否する。 -
返る。
注: 書き込み処理中のハッシュは、 意図的に存在しないハッシュと同じようには振る舞わない。これにより、呼び出し元が進行中の書き込みを真のキャッシュミスと誤認し、 単にそのファイルを書き込む目的だけで、非常に大きなファイルの冗長な同時ダウンロードを 開始することを防ぐ。§ 3.3 ファイルの作成と書き込みを参照。
-
-
disclosableEntry を、entry および origin を与えて可用性 ゲーティングを適用する処理を実行した結果とする。
-
disclosableEntry が null の場合:
-
global を与えて、DOM 操作タスクソース上にグローバルタスクをキューに入れ、 result を "
NotFoundError"DOMExceptionで 拒否する。 -
返る。
-
-
handle を、realm 内で、その ロケーターが Cross-Origin Storage ファイルシステム内の disclosableEntry を指す、新しい
FileSystemFileHandleを作成した結果とする [FS]。 -
handle のCOS オリジンを origin に設定する。
-
handle の読み取り可能を true に設定する。
注: このハンドルはすでに可用性ゲーティングを適用する処理を通過しているため、呼び出し元オリジンには エントリーの バイト列を取得する権利がある。
-
global を与えて、DOM 操作タスクソース上にグローバルタスクをキューに入れ、 result を handle で 解決する。
-
entry が null の場合、null を返す。
-
origin が entry の保存 オリジンに含まれる場合、entry を返す。
注: 元の保存元、およびそのエントリーを 自身で正常に書き込んだ任意のオリジンは、 常にそれを読み戻すことができる。§ 3.4.1 元の保存元の アクセスを参照。
-
entry のオリジンが "
*" の場合:-
entry のハッシュがPHL 上にない場合、null を返す。
注: Public Hash List ゲートは、 ここでのみ、すなわちグローバルスコープのエントリーに適用される。これは、 そうでなければ開示が Web 上の任意のオリジンに及び得る唯一の 場合である。以下のリストスコープおよび同一サイトスコープの場合には適用されない。保存オリジンはそれらについてすでに 明示的で 範囲の限定された開示判断を行っており、それに加えて別個のグローバルな遍在性を要求すると、 通常の制限付き共有(§ 3.4 リソース可視性のアップグレードを参照)が、 しばしば専有リソースであるものに対する 無関係な公開キュレーションに依存することになる。§ 7.2 クロスサイトプロービングを参照。
-
entry を返す。
-
-
null を返す。
-
disclosable を、entry および origin を与えてCOS 開示を決定する処理を実行した結果とする。
-
disclosable が null の場合、null を返す。
-
origin が disclosable の保存 オリジンに含まれる場合、disclosable を返す。
-
ユーザーエージェントがこのリクエストにGREASE’ingを適用することを選択した場合、 null を返す。
-
disclosable を返す。
3.3. ファイルの作成と書き込み
A FileSystemFileHandle
created by 作成リクエストを完了するには、関連付けられた
要求オリジンがあり、これはハンドルへの
書き込みが正常に完了したときに、検証して保存するが
エントリーのオリジンをアップグレードしようとする値である。
COS エントリーを指すすべての FileSystemFileHandle
には、さらに関連付けられた
COS オリジン、すなわちそれを取得したオリジンと、関連付けられた
読み取り可能ブール値があり、これは
getFile()
がその特定のハンドルを介してエントリーのバイト列を開示できるかどうかを制御する。
これは、すでに
可用性ゲーティングを通過した読み取りリクエストを完了するによって返されるハンドルでは true であり、
作成
リクエストを完了するによって返されるハンドルでは、その同じハンドルについて検証して保存するが成功するまで false である。
注: これは意図的にエントリーではなくハンドルのプロパティである。
作成リクエストは、
エントリーがすでに存在し、すでに "written" であるかどうかにかかわらずハンドルを返す(
作成
リクエストを完了するを参照)。そのため、エントリー単位の規則では、任意のオリジンが
requestFileHandle()
を
create:
true で呼び出し、自身が一度も書き込んでいないエントリーを直ちに読み取り、
オリジン、
PHL メンバーシップ、またはGREASE’ingを満たすことなく、その内容を知ることができてしまう。この
仕様のすべての開示制御は読み取り経路で適用されるため、エントリー単位でゲーティングすると、作成リクエストによって
それらすべてを回避できてしまう。呼び出し元に最初に正しいバイト列を提供することを要求すれば、
作成によって取得したハンドルを介した読み取りが成功しても、呼び出し元がすでに持っていなかったものは何も開示されない。
CrossOriginStorageRequestFileHandleOptions
options、グローバルオブジェクト
global、および Realm realm を与えて、作成
リクエストを完了するには、次を行う:
-
requestedOrigins を、 options["
origins"] を与えて要求 オリジンを正規化する処理を実行した結果とする。 -
entry を、COS レジストリ内の、そのハッシュが hash と等しい COS エントリーが存在する場合はそのエントリーとし、それ以外の場合は null とする。
-
entry が null の場合:
-
entry の保留中のライター数を 1 増加させる。
注: これは、呼び出し元が
createWritable()を一度も呼び出さない場合や、結果として得られたストリームを一度も閉じない場合でも、handle を 未完了のライターとして追跡する。このように 放棄されたハンドルは entry に対して恒久的にカウントされる。これは、この仕組みが存在する以前に、 放棄された進行中の書き込みによって entry が恒久的に "pending" のままになっていたのとまったく同じである。 検証して 保存するを参照。 -
handle を、realm 内で、その ロケーターが Cross-Origin Storage ファイルシステム内の entry を指す、新しい
FileSystemFileHandleを作成した結果とする [FS]。 -
handle のCOS オリジンを、global の 関連設定オブジェクトのオリジンに設定する。
-
handle の要求オリジンを requestedOrigins に設定する。
-
handle の読み取り可能を false に設定する。
注: handle は、 entry がすでに存在していたかどうか、および すでに "
written" であるかどうかにかかわらず返される。呼び出し元は引き続き handle を介して完全なファイルのバイト列を提供する必要がある。これにより、書き込みを以前から存在していたことの検出に使用できないようにし( § 7.2 クロスサイトプロービングを参照)、さらに、より寛容な オリジン 値のリクエストを受け入れる前に検証できるようにする。 § 3.4 リソース可視性のアップグレードを参照。 -
global を与えて、DOM 操作タスクソース上にグローバルタスクをキューに入れ、 result を handle で 解決する。
*"、リストのオリジン、または null を返す:
-
origins が存在しない場合、 null を返す。
-
origins が "
*" の場合、"*" を返す。 -
list を « » とする。
-
origins の各 candidate について反復する(単一の 文字列は、1 要素のリストとして 扱う):
-
candidateOrigin を、candidate に対して基本 URL パーサー を実行して得られたオリジンとする。
注: COS リクエストを検証する処理によって、各 candidate が 不透明でないオリジンとして解析されることはすでに確認されている。
-
list が candidateOrigin を含まない場合、candidateOrigin を list に付加する。
-
-
list を返す。
注: 後で既存のエントリーにマージする ときだけではなく、ここで重複を除去することにより、エントリーが 最初に作成された時点からオリジンには重複がなくなるため、それ以降に行われるすべての複製でも重複がない状態が維持される。
ロケーターが
COS エントリーを指すハンドル上で
createWritable()
を呼び出すことで取得された FileSystemWritableFileStream
が閉じられたとき [FS]、ユーザーエージェントは
その終了操作の promise が履行される前に、以下の検証して保存する
手順を実行しなければならない。
注: これは、終了がどのように
引き起こされたかにかかわらず適用される。すなわち、明示的な
close()
呼び出し、またはソースの終端に到達する
pipeTo()
呼び出しであり、後者もデフォルトでは宛先を閉じる。[STREAMS]は、ストリームが閉じられる時点で両者を
区別せず、このアルゴリズムも区別しない。
-
computedValue を、[WEBCRYPTO]に従い、 entry のアルゴリズムによって指定された アルゴリズムを使用して計算した、bytes の小文字 16 進ダイジェストとする。
-
computedValue が entry の値と厳密に等しくない場合:
-
終了操作の promise を "
DataError"DOMExceptionで 拒否する。 -
次の手順を Cross-Origin Storage キューにエンキューする:
-
entry の保留中のライター数を 1 減少させる。
-
entry の状態が "
pending" で、かつ entry の 保留中のライター数が 0 の場合、 entry のハッシュを COS レジストリから削除する。注: これにより、 失敗した書き込みは、恒久的に到達不能な "
pending" エントリーを残すのではなく、自身の後始末を行う。同じハッシュに対する後続のrequestFileHandle()呼び出しは、他の ライターが未完了でなくなった時点で、エントリーをまったく認識せず、無期限の "NotAllowedError" ではなく、通常の "NotFoundError" を受け取る。 このカウントは、 同じハッシュについて同時に進行中の別のライター(たとえば、 2 つのタブがどちらもハッシュが存在しないことを確認し、それぞれ独立して書き込みを開始した場合)が、 まだ正常に書き込む可能性のあるエントリーを 削除することを防ぐ。そのライターがまだ未完了であるか、 すでに成功している場合、カウントがまだ 0 に達していないか、 entry の 状態がもはや "pending" ではないため、 この手順は何もしない。すでに "written" であるエントリーは、後から 何人のライターがそれを要求して失敗したかにかかわらず、この方法では決して削除されない。一度も正常に 書き込まれていないエントリーだけが対象となる。
-
-
これらの手順を中止する。
-
-
次の手順を Cross-Origin Storage キューにエンキューする:
createWritable()
が、
COS エントリを指す FileSystemFileHandle
に対して呼び出された場合、
FileSystemWritableFileStream
を生成しなければならず、その内容は空の状態から開始されなければならない。
これは、keepExistingData
の値、および
対象エントリの状態に関係なく適用される。
注: [FS] では、それ以外の場合、keepExistingData
は、既存ファイルの内容を
ストリームの初期内容として設定するものと定義されている。ここでそれに従うと、呼び出し元は自身が一度も保持していなかったバイトの保存元
オリジンになることができてしまう。create 要求は、エントリが
すでに存在するかどうかにかかわらずハンドルを返すため、呼び出し元は別のオリジンが保存したハッシュに対する writable を開き、何も
書き込まずに閉じることで、引き継がれたバイトのハッシュを要求された値に一致させることができる。これにより、
オリジン、公開ハッシュリスト、および
GREASE 処理が一度も参照されないまま読み取りアクセスが与えられることになる。これは、個別には許可されている2つの操作を組み合わせて成立する可用性
ゲーティングの回避である。同じ理由により、
検証して保存では、
create 要求のたびに完全な内容が必要となる。
注: したがって、書き込みを一度も行わずに閉じられた writable は
空のバイト列を保持することになり、これは呼び出し元が必要とするどのエントリについても
要求された値にはハッシュされないため、検証して保存は
"DataError"
DOMException
で拒否する。これは、他の不一致の場合と同様である。その場合に
代わりにストレージまたは I/O の失敗を報告する実装は、検証結果を無関係な
エラーの背後に隠すことになる。
ファイルシステム標準
[FS] では、依存する
仕様が FileSystemWritableFileStream の
closing 手順に追加の書き込みごとの検証を組み込むための拡張ポイントをまだ定義していない。そのようなフックが存在するようになるまでは、この節で必要な動作を直接記述する。将来の
改訂では、[FS] と正式に統合されることが期待される。
3.4. リソースの可視性の拡張
COS エントリの可視性は 拡張できるが、縮小することはできない。
*"、リストである
オリジン、または null の requestedOrigins が与えられたときに、リソースの
可視性を拡張するには:
-
requestedOrigins が null の場合、return する。
注:
originsを省略しても、既存の エントリの範囲が狭まることはない。これは同一サイトでの可用性を要求するだけであり、すべてのエントリはすでに少なくとも それと同程度の可用性を持っている。 -
entry のオリジンが "
*" の場合、return する。注: すでにグローバルに利用可能なエントリを 後から書き込む者が制限することはできない。この 注記が適用され、requestedOrigins が "
*" でない場合、ユーザーエージェントは 要求された制限が適用されなかったことを開発者に知らせるコンソール 警告を記録することが期待される。 -
requestedOrigins が "
*" の場合:-
entry のオリジンを "
*" に設定する。 -
Return する。
-
-
entry のオリジンが null の場合:
-
entry のオリジンを requestedOrigins に設定する。
-
Return する。
-
-
requestedOrigins の各 candidateOrigin について反復する:
-
merged が candidateOrigin を含む場合、continue する。
-
merged のサイズ がユーザーエージェントのオリジンリストの最大長と等しい場合、 break する。
注: 残りの candidateOrigin 値は、この拡張を失敗させるのではなく、この拡張から暗黙に破棄される — 書き込み自体はすでに成功している — が、ユーザーエージェントは エントリのオリジンリストが上限に達していることを示すコンソール警告を記録することが期待される。
-
candidateOrigin を merged に付加する。
-
-
entry のオリジンを merged に設定する。
注: 元の保存元だけでなく、新しいサイトも、 エントリのオリジンを拡張できる。ただし、 そのエントリのハッシュになるバイトも提供することが条件である。これは意図的である: あるハッシュに対応する正しいバイトをすでに保持している任意のサイトは、構造上、そのハッシュが何を表すかについて 元の保存元と同等に権威がある。
3.4.1. 元の保存元によるアクセス
オリジンが 書き込みを正常に完了した COS エントリ — すなわち、
エントリの保存元オリジンに含まれる任意のオリジン — は、その後いつでも
requestFileHandle()
を介してそのハンドルを取得できる。これは、エントリの
オリジンの値とは無関係であり、
そのハッシュが PHL 上にあるかどうかとも無関係である。
これは、オリジンが自身の保存したものには常にアクセスできる Cache API のモデルを反映している。
4. オリジン間ストレージファイルシステム
クロスオリジンストレージファイルシステムは、あらゆる オリジンのバケットファイルシステムやローカルファイルシステムアクセスのルートとは異なるファイルシステムルートであり、その エントリは、COS レジストリのCOS エントリ項目と一対一に対応する。
クロスオリジンストレージファイルシステムは、[FS]の通常の呼び出しごとの
権限チェック
モデルを使用しない。そこから取得されたすべてのFileSystemFileHandle
は、スクリプトに返される前に
§ 3.2 ファイルの読み取りまたは§ 3.3 ファイルの作成と
書き込みによってすでに完全に認可されているため、そのようなハンドルに対して
getFile()
またはcreateWritable()
を呼び出しても、
追加の権限プロンプトが発生することはない。
したがって、そのようなハンドル上のqueryPermission()およびrequestPermission()は、
プロンプトを表示できないため、
"prompt" を報告してはならない。それらは、作成要求によって取得されなかった
ハンドルの書き込みモードについては "denied" を報告し、それ以外の場合は
"granted"
を報告しなければならない。
注: 書き込みは、ハンドルが
実際に欠いている可能性がある唯一の能力である。作成要求だけが、
書き込み可能なハンドルを生成するため、他の任意のハンドルの書き込みモードについて "granted" を報告すると、
createWritable()
が拒否する能力を有すると主張することになる。読み取りは
"granted" のままである。読み取り可能なハンドルを保持する呼び出し元は、そのハンドルを通じて読み取ることができるためである。要求しても、
表示するプロンプトもなく、許可を記録できる状態もないため、
どちらの結果も変更できない。
読み取り可能が false である
COS エントリを指す
FileSystemFileHandle
に対してgetFile()
を呼び出した場合、
"NotAllowedError"
DOMException
で拒否しなければならない。
これは、次の2つの異なるケースを対象とする:
-
エントリがまだ "
pending" である作成要求から得られたハンドル。これは、同じハッシュに対する同時のrequestFileHandle()呼び出しが拒否されるのと同じ理由による( § 3.2 ファイルの読み取りを参照)。呼び出し元は、 まだ検証されていないプレースホルダーを ファイルの実際の内容であるかのように観測できてはならない。 -
別の他のオリジンがすでに書き込んだエントリに対する作成要求から得られたハンドル。その エントリの状態は "
written" であるが、この呼び出し元はそのバイトを提供しておらず、 可用性ゲーティングも通過していないため、 エントリについて何も知ることができてはならない — その エントリが存在するかどうかも含む。
ハンドルの読み取り可能が true になると、そのハンドルに対して呼び出されたgetFile()
は、対象エントリのバイトを内容とするFile
を返す。これは、
[FS]が、そのバイトを
バイナリデータとして持つファイル
エントリについてすでに定義している動作とまったく同じである。
COS エントリを指すFileSystemFileHandle
は、
パス
が、単一の文字列、すなわちエントリの
COS ハッシュの値を含むリストであり、そのルートが
クロスオリジンストレージファイルシステムであるファイルシステムロケーターを持つ。
注: [FS]は、name
を、ハンドルの
ロケーターのパスの最後のパス成分として定義しているため、これはname
を選択に委ねるのではなく確定する。それは
ハッシュである。エントリにはそれ自体の名前がなく、ハッシュが唯一の識別情報であるため、
それを報告することで、空文字列なら失われる情報を保持できる。
エントリには名前も包含ディレクトリもないため、[FS]の構造的な機能の大半には 操作対象がない。識別性は例外であり、コンテンツアドレス指定されたエントリが 常に答えられる唯一の問いである。COS レジストリは、各COS ハッシュについて最大1つのCOS エントリしか保持しないため、2つの ハンドルは、それらのハッシュが等しい場合に限り同じエントリを指す。
COS エントリを指すFileSystemFileHandle
に対してisSameEntry()
を呼び出し、その引数も
COS エントリを指し、かつ同じ
オリジンによって取得されたものである場合、2つのハンドルのCOS ハッシュ項目が等しければ true を返し、そうでなければ false
を返さなければならない。
注: これを拒否すると、ユーザー エージェントがすでに保持している情報を捨てることになる。
呼び出し元のオリジンが取得していない引数、
またはクロスオリジン
ストレージファイルシステム以外のファイルシステムを指す引数を指定してisSameEntry()
を呼び出した場合、拒否しなければならない。
注: その場合に false を返すと、 2つのハンドルが異なるエントリを指していると断言することになるが、 これは呼び出し元オリジンに検査する権限のないハンドルについての主張である。拒否は単に、 比較を行えなかったことだけを示す。
COS エントリを指す
FileSystemFileHandle
に対してmove()およびremove()を呼び出した場合、
"NotAllowedError"
DOMException
で拒否しなければならず、
エントリを変更せずに残さなければならない。
注: エントリは、その保存元 オリジン内のすべてのオリジンによって共有されるため、 削除を認めると、あるサイトが他のサイトの依存するデータを破壊できてしまう。削除は 追い出しおよびユーザー自身のストレージ制御に属する。名前変更や親の変更には 操作対象がない。エントリはそのCOS ハッシュによって名前付けされ、包含ディレクトリを持たないためである。
注: 執筆時点では、どちらのメソッドも[FS]にもファイルシステム
アクセス API にも定義されていない
(WICG/file-system-access#214)。
したがって、エラー名は、[FS]が
エントリを削除する操作として定義しているremoveEntry()
に従う。これは、readwrite アクセスが
許可されていない場合、アクセス結果のエラー名で拒否する。ここでは、存在しないのではなく拒否されるという解釈が正確である —
これらの操作には意味があり、拒否される。
createSyncAccessHandle()
については、ここで規則を定める必要はない。その手順は、ハンドルがバケットファイルシステム内にない場合は常に、
"InvalidStateError"
DOMException
で拒否し、
クロスオリジンストレージファイルシステムは、あらゆるオリジンのものとは異なるファイルシステムルートであるため、
[FS]がすでに
拒否とその名前の両方を決定している。
注: これは、この仕様が独立に定める場合にも
望ましい結果である。
FileSystemSyncAccessHandle
は呼び出し元に書き込み可能なファイル記述子を渡すため、
エントリのバイトを、
それらが対応付けて保存されているCOS ハッシュと整合しない状態に
変更できてしまい、
そのエントリを開示可能な他のすべてのオリジンも同じバイトを読み取る。
4.1. ハンドルの転送
FileSystemFileHandle
はシリアル化可能オブジェクト [FS] であるため、
COS エントリを指すものは、別の環境設定オブジェクトに、たとえば
postMessage(message, options)
を使用して渡すことができる。
これは、
requestFileHandle()
と並んで、そのようなハンドルを取得する第2の方法であるため、
ここでも制約される。
シリアル化手順は、COS エントリを指すFileSystemFileHandle
について、value および serialized が与えられたとき、さらに次を行う:
逆シリアル化手順は、serialized、 value および realm が与えられたとき、さらに次を行う:
-
serialized.[[COSOrigin]] が realm の 環境設定オブジェクトのオリジンと同一オリジンでない場合、 "
DataCloneError"DOMExceptionを投げる。 -
value のCOS オリジンを serialized.[[COSOrigin]] に設定する。
-
value の読み取り可能を serialized.[[COSMayRead]] に設定する。
注: 同一 オリジンチェックがなければ、転送によって この仕様のすべての開示制御が一度に無効化されてしまう。読み取り可能が true のハンドルは、 すでに 可用性ゲーティングを適用をそれを要求したオリジンに対して通過している。これを別の オリジンに送信すると、そのオリジンについてオリジン、 PHL メンバーシップ、またはGREASE 処理が一度も評価されないまま、そのオリジンにエントリのバイトを渡すことになる。これは、 同様に同一オリジンの受信者に対してのみ有用であるハンドルについての、ファイルシステム標準の既存の扱いと一致する。
注: 読み取り可能は 再計算されるのではなくハンドルとともに移動するため、 書き込みが行われていない作成要求のハンドルは転送後も読み取り不能のままであり、 読み取り要求のハンドルは再度ゲーティングされることなく読み取り可能なままである。到着時に再ゲーティングすることは、 改善ではなく悪化となる。同じ ハンドルを転送することで、呼び出し元が可用性を繰り返し探ることができてしまうためである。
5. ストレージ管理
5.1. ストレージ制限
ユーザーエージェントは、単一のオリジンが他のオリジンのエントリを追い出そうとして
キャッシュをあふれさせることを防ぐため、オリジンが成功した書き込みを通じて
COS レジストリに提供できる総バイト数に上限を
設けなければならない。具体的な上限は
実装定義である。オリジンの書き込みがその
上限を超える場合、ユーザーエージェントは
拒否し、
"QuotaExceededError"
DOMException
とし、コンソールに警告を記録するべきである。
注: エントリはコンテンツアドレス可能であるため、同じ バイトを同じハッシュの下に繰り返し書き込むオリジンは、最初の成功した書き込みを超えて追加のクォータを消費しない。§ 2.2 COS エントリを参照。
ユーザーエージェントはまた、実装定義のオリジンリストの最大長を持つ。これは、
単一のオリジンのリストに含めることができるオリジンの数を制限する
正の整数である。これは、リストが最初に指定されるとき(COS 要求を検証するを参照)
と、後で既存のエントリにマージされるとき(
リソースの可視性を拡張するを参照)の両方で適用されるため、単一の呼び出しでも、
時間の経過に伴う多数の呼び出しの累積的な影響でも、エントリのオリジンを無制限に
増大させることはできない。メモリ使用量を制限することに加えて、これはオリジンのリストが
"*" の未宣言の代替として利用されることも防ぐ。§ 7.2 クロスサイトプロービングを参照。
この上限を超えた場合の処理は、これら2つの場所で異なる。2つの呼び出しが 操作の非常に異なる時点で発生するためである:
-
COS 要求を検証するでは、ファイルが取得、ハッシュ化、または 書き込まれる前に上限がチェックされる。これを超えた呼び出し元は直ちに "
TypeError" を受け取り、それ以外は何も起こらない —他の不正なorigins値と同じ扱いである。 -
リソースの可視性を拡張するでは、この上限に達するのは、 別々の独立した書き込み呼び出しで要求されたオリジンの累積的な影響によってのみであり、場合によっては無関係なオリジンによる 長期間にわたる呼び出しの結果である。また、この上限がチェックされるのは、この呼び出しのバイトがすでにハッシュ化、 検証され、永続的に保存された後だけである。その時点で書き込みを拒否すると、無関係な管理上の上限を理由に、 成功してすでに検証済みの — そして潜在的には非常に大きな — 書き込みを破棄することになり、 しかも単一の呼び出し元の誤りに帰属させることすらできない。したがって書き込みは 成功したままとし、容量を超えるオリジンのみがオリジンから破棄され、 コンソール警告が記録される。これは既存の より許容的な状態からより制限された状態への要求の処理を踏襲する。完全には満たせないオリジン要求は、 それを伴った書き込み自体の失敗に変換されるのではなく、暗黙に上限までに制限される。この仕様の他の箇所にある § 7.3 可用性ゲーティングと一致して、 呼び出し元には、要求したオリジンが 実際に追加されたかどうかを事後に確実に確認する方法はない。その オリジンとして後続の
requestFileHandle()呼び出しを行っても、オリジンが追加されていた場合でも失敗する可能性がある — たとえば GREASE 処理によって — ため、その結果をいずれかを確認するものとして解釈してはならない。
5.2. 削除
この節は非規範的である。
ストレージ逼迫時には、ユーザーエージェントはエントリをCOS レジストリから追い出してよい。 たとえば、各エントリに最も最近アクセスした保存元オリジン全体にわたって 最終使用時刻が最も古いものを優先するポリシーを使用できる。ユーザーエージェントは、 ユーザーがどのファイルが保存されているか、各ファイルにどのオリジンがアクセスしたかを確認し、 エントリを手動で削除したり、すべてのクロスオリジンストレージデータを消去したりできる設定 UI を 提供することが期待される。
ユーザーがオリジンのサイトデータを消去した場合、ユーザーエージェントは、そのオリジンが含まれるすべての 保存元 オリジン集合からそのオリジンを削除するべきである。その削除後、COS エントリの 保存元 オリジンが空になった場合、ユーザーエージェントはそのエントリを削除対象として考慮してよい。
5.3. 手動で追加されたエントリ
この節は非規範的である。
上記の設定 UI では、ユーザーがすでにディスク上に持っているファイルを直接
クロスオリジンストレージに追加できるようにしてよい — たとえば、どのウェブサイトとも無関係にダウンロードした AI モデルなど —その際、
スクリプトが requestFileHandle()
を呼び出すことはない。そのようなエントリには、
書き込みの帰属先となる要求元のオリジンが存在しないため、命令型
API だけでは答えられない2つの問題が生じる:
-
§ 3.4.1 元の保存元アクセスの目的において、 元の保存元は誰か? 誰もいない。エントリの保存元オリジンは、書き込みを行ったオリジンを含むのではなく、 空の状態から開始する。したがって、要求を行うすべてのオリジンが通常従う 可用性ゲーティングおよびオリジンチェックを免除されるオリジンは 存在しない — 実際にどのオリジンもそのバイトを書き込んでいないため、これは正しい結果である。
-
オリジンは、
originsを省略した通常の書き込みの場合と同様に、デフォルトで同一サイトのみにするべきか? いいえ。「同一サイト」は要求元オリジンとの関係においてのみ意味を持つが、 手動追加には要求元オリジンがないため、「同一サイト」が意味するサイトが存在しない。 代わりに、ユーザーエージェントはそのようなエントリのオリジンをデフォルトで "*" にすることが期待される。これは、ファイルを手動で事前登録する目的 — ユーザーがまだ訪問していないサイトでも、 ユーザーがすでにディスク上に持っているファイルを再利用できるようにすること — は、他のオリジンが実際にそのファイルを 発見できる場合にのみ達成されるためである。ユーザーエージェントの設定 UI では、さらにユーザーがより狭い範囲を選択できるようにしてよい。
この方法で追加されると、状態が "written" のエントリは、それ以外の点では
ウェブサイトが requestFileHandle()
を介して書き込んだものと区別できない。同じ
可用性ゲーティングおよび可視性
拡張の規則が適用され、同じ
オリジン値を持つ他の任意のエントリの場合とまったく同様である —
エントリが最終的に "*" スコープになる場合のPHL 上にあるチェックも
含まれる。これは手動追加のデフォルトではあるが、唯一の可能な結果ではない。
5.4. 来歴メタデータ
この節は非規範的である。
COS エントリは、そのバイトが どこから来たのかについて、意図的に何も記録しない。識別情報は ハッシュだけである。同じバイトは、 いくつのオリジンがそれを保存したか、またはいくつの URL から取得されたかに関係なく同じエントリである (§ 2.2 COS エントリを参照)。URL はエントリではなく、ある 書き込み元による取得のプロパティであるため、複数のオリジンが書き込んだエントリについて1つを選ぶ非恣意的な方法はない。 URL はバイトのように検証可能でもない(§ 7.1 リソースの完全性を参照)。 また、パスやクエリ文字列は特定のドキュメント、 アカウント、またはセッションを識別できるため、保存元 オリジン内の粗粒度なオリジン値よりも、ユーザーの閲覧についてかなり多くの情報を含む。 したがって、それをエントリに記録すると、高エントロピーなシグナルが、 オリジンと§ 7.3 可用性 ゲーティングが課すために存在する開示制限を迂回することになる。
それを求める動機自体はそれでも現実的である。§ 5.2 追い出しで説明した
設定 UI で数ギガバイトのファイルを確認しているユーザーも、
requestFileHandle()
呼び出しが失敗した理由をデバッグしている開発者も、そのファイルが
どこから来たのかを知りたいだろう。ユーザーエージェントは、エントリと並行して実装内部の来歴記録を保持することで、
これに対応してよい — たとえば、その保存元オリジンのそれぞれが
バイトを取得した
URL とその時刻 — ただし、その記録をエントリの一部ではなくユーザーエージェントの状態として扱うことを条件とする:
-
それはスクリプトには決して公開されない。この仕様にはそれを開示するものは何もなく、後から追加されるものも 開示するべきではない。
requestFileHandle()も、それが返すFileSystemFileHandleも、そのような記録が存在するかどうかを明らかにするべきではなく、ましてその 内容を明らかにするべきではない。特に、要求元のオリジンは、自身が 生成していない記録を観測できてはならない。 -
それは、信頼された非 Web サーフェスを通じてのみ提示される。すなわち、ユーザーエージェント自身の設定およびストレージ 検査 UI、その開発者ツール、そして — ユーザーエージェントに拡張機能プラットフォームがある場合 —明示的にユーザーが許可した権限によって制御される拡張機能 API であり、閲覧履歴を公開する他の API と同等に扱われる。検討されている拡張機能サーフェスについては、この リポジトリのブラウザー拡張機能統合ポイントの解説を参照。
-
それは未検証であり、そのようなものとして提示される。その中の URL は、その バイトを書き込んだオリジンによる主張であって、それらについての証明ではない — 内容を保証するのはハッシュだけである( § 7.1 リソースの完全性を参照)。2つのオリジンが同じエントリについて 異なる URL を記録することもあり、どちらかが 不正確であったり、意図的に誤解を招くものであったりする可能性もある。
-
それは、エントリ、およびそれが帰属するオリジンと同じ存続期間を持つ。エントリが追い出されるか削除されると それも破棄され、あるオリジンに帰属する部分は、そのオリジンが保存元オリジンから削除されたときに破棄される。これには、ユーザーが その オリジンのサイトデータを消去した場合も含まれる(§ 5.2 追い出しを参照)。
このような記録はコンテンツから見えないため、ユーザーエージェントがそれを保持するかどうか、およびどの程度 保持するかは、完全に実装に委ねられる。この仕様にはそれに依存するものは何もなく、その 存在または不在をサイトが検出することはできない。
6. 権限ポリシーとの統合
この仕様は、文字列 "cross-origin-storage" によって識別されるポリシー制御機能 [permissions-policy]を定義する。
その既定の許可リストは self である。
この機能を使用することを許可されていないDocumentでは、そのDocumentから(または所有者がそのDocumentである
worker から)行われるすべての
requestFileHandle()
呼び出しが、ハッシュの検証、レジストリの検索、または書き込みが行われる前に、"NotAllowedError"
DOMException で拒否される。
7. プライバシーおよびセキュリティに関する考慮事項
この節は、RFC 2119 のキーワードを使用する箇所を除き、非規範的です。リポジトリ内の セキュリティおよびプライバシー質問票も参照してください。
7.1. リソースの完全性
すべてのCOS エントリは暗号学的ハッシュをキーとし、その
バイトはそのハッシュに対して検証される(
§ 3.3 ファイルの作成と書き込みを参照)。したがってサイトは、
requestFileHandle()
を通じて取得したファイルが、hash を自身で取得した場合に得られるものと
完全に同じバイトを持つことを確信できる。開発者はクロスオリジンストレージの内容を列挙することも、
そのハッシュをすでに知っていないファイルにアクセスすることもできない。
COS ハッシュは秘密ではない。それは コンテンツ識別子であり、すでにファイルを持っている者なら誰でも簡単に計算でき、 この仕様が対象とする種類の広く配布される リソースについては日常的に公開情報となっている — たとえば、モデルやライブラリの リリースとともに公開される。したがって、ハッシュを知っていればエントリを検索するには十分だが、ケイパビリティ URL やベアラートークンとは異なり、それ自体ではアクセスを許可しない。検索が成功するかどうかは、ハッシュがたまたま 非公開のままだったかどうかではなく、完全にオリジンと§ 7.3 可用性ゲーティングによって決定される。 開発者は、未公開のハッシュをアクセス制御メカニズムとして扱ってはならない。特定のファイルに関心を持つ 攻撃者は、そのハッシュを推測する必要はなく、ファイル 自体を入手するだけでよい(§ 7.2 クロスサイトプロービングを参照)。
7.2. サイト間プロービング
リソースが限られた一部のサイトでしか使用されていない場合、そのリソースがクロスオリジンストレージに
存在することを知ることができる攻撃者は、ユーザーがそれらのサイトのいずれかを訪問した可能性が高いと推測できる。
requestFileHandle()
は存在を知るための仕組みであるため、各呼び出しは
実質的にはプローブである。この仕様にある 2 つの独立した仕組みにより、プローブが
知ることのできる範囲が制限される:
-
オリジン( § 3.4 リソースの可視性の拡張を参照)により、保存元 オリジンは 開示を選択したオリジンの集合に制限できるため、独自のリソースや利用頻度の低いリソースを グローバルにプローブ可能にする必要はまったくない。
-
§ 7.3 可用性ゲーティングはさらに、 "
*" スコープのリソースについて、そのハッシュがPHL 上にある場合を除き、 その保存元オリジン外の要求元オリジンへの開示を差し控えるため、origins: "*" で保存されたリソースが Web 上のすべてのオリジンから自動的にプローブ可能になることはない。このゲートは "*" スコープの エントリにのみ適用される。リストおよび同一サイトスコープのエントリでは、保存元オリジンがすでに それらの開示範囲を明示的に制限しているため、最初の箇条書きの制限だけが唯一の ゲートとなる。
最初の箇条書きが成り立つのは、「選択されたオリジンの集合」が Web より有意に小さいままである場合に限られる。
origins の形式には、呼び出し元が
非常に多数のオリジンを列挙することを妨げるものはない — たとえば、公開されている
トップサイトのランキングから組み立てたリストなど — これは、"*" のみが必要とする
意図的かつ明示的なオプトインを回避しながら、機能的にはグローバルな開示に近似することになる。オリジンリストの最大
長(
§ 5.1 ストレージ制限を参照)がこれを制限する。真の
複数プロパティのユースケース
(共通の管理下にある少数の関連オリジン)を収容するには十分小さく、それでも「すべてのオリジン」の意味のある近似には
はるかに及ばない上限にすることで、オリジンの制限付きオリジン形式が
"*" の未宣言の代替として利用されることを防ぐ。
ユーザーエージェントはさらに、単一のオリジンからの
requestFileHandle()
の繰り返し呼び出しをレート制限するか、その他の方法でスロットリングするべきであり、
プローブ対象のハッシュがPHL 上にあるかどうかにかかわらず、
プローブの試みを識別してブロックするために、オンデバイスのヒューリスティクス
(たとえば、ユーザーごとに生成されているように見えるハッシュに対するリクエストのパターンを検出すること)を適用してもよい。
requestFileHandle()
呼び出しと併せてカウントされる場合に限られます。なぜなら、
スクリプト可能な統合は、それらを同じように容易にループ内で発行できるためです。
7.3. 可用性ゲーティング
requestFileHandle()
による読み取りが、保存元
オリジン外のオリジンから成功するかどうかは、要求元オリジンが
エントリを読み取ることを許可されているかどうかに常に依存し、これはオリジンによって決まる。"*" スコープのエントリでは、これとは別の
独立した問題も適用される。すなわち、ユーザーエージェントがそのエントリがそもそも
存在することを開示する意思があるかどうかであり、これはPHL
メンバーシップおよびGREASE 処理によって決まる。そのようなエントリでは両方が
成立しなければならない。リストまたは同一サイトスコープのエントリでは、最初の問題だけが適用されるが、
GREASE 処理によって、オリジンが本来
許可する開示が抑制されることはある。規範的アルゴリズムについては§ 3.2 ファイルの読み取りを参照。したがって、"NotFoundError"
は、リソースが存在しないことの
証拠ではない。リソースが存在しない、要求元
オリジンが対象範囲外である、"*" スコープのリソースのハッシュが PHL 上にない(まだ、または今後も)、あるいは
GREASE 処理が真陽性を抑制したことを意味する可能性がある。開発者は "NotFoundError"
を
「ネットワークにフォールバックする」より具体的な意味として扱ってはならない。
注: "*" スコープのエントリの開示は、
現在のコンテキストでサードパーティ Cookie を設定または読み取ることができる要求元
オリジンにさらに制限される。そのような
エントリは、サードパーティ Cookie を利用できないオリジンには、
PHL メンバーシップに関係なく開示されない。これは、PHL
メンバーシップだけでは塞げない抜け穴を塞ぐ。攻撃者は、
個別には通常の PHL 対象となり得るリソースのうち、どの部分集合を書き込むかを選択することで、クロスサイト識別子を
構築できる。そして、その結果生じるプローブが通常のトラッキング Cookie よりも多くの情報を与えるかどうかを決める要因は、
サードパーティ Cookie を利用できるかどうかである。
7.4. GREASE の適用
ユーザーエージェントは、GREASE を適用してもかまいません(ランダムな拡張を生成して 拡張性を維持する)。これは、§ 7.3 可用性ゲーティングが本来開示を 許可する場合でも、開示可能なエントリが存在しないかのように時折応答することです。これによりノイズが加わり、 サイトが実際の不存在と、プライバシーを目的とする偽陰性を区別しにくくなります。これは、 UA クライアント ヒントで適用される手法に似ています。
GREASE を適用するユーザーエージェントは、対象エントリのサイズに応じた適切な判断を行わなければなりません。 小さいエントリでは、ネットワーク取得へのフォールバックが低コストであるため、時折生じる偽陰性は妥当なプライバシー上のトレードオフです。 ユーザーエージェントは、誤った再ダウンロードのコストが得られるプライバシー上の利益に明らかに不釣り合いとなるサイズのエントリに対して、 GREASE を適用してはなりません。たとえば、ギガバイト規模の AI モデルの重みです。この場合、偽陰性によって、 安価な再取得ではなく、完全で観測可能かつ高コストな再ダウンロードが強制されるためです。
7.5. フィンガープリンティング
攻撃者がオリジン間ストレージのプロービングから抽出できる情報は、プローブ対象リソースの人気度によって制限されます。 一般的な AI モデルや広く使用される JavaScript ライブラリなど、非常に人気の高いリソースをユーザーが持っていることを知っても、 ユーザーがそれを使用する多数のサイトのいずれかを訪問したことしか分かりません。一方、まれまたは一意のリソースを持っていることを知ると、 はるかに多くの情報が得られます。ユーザーエージェントは、ハッシュがユーザーごとに意図的に一意になるように見えるリソースを検出するため、 端末上のヒューリスティックを適用することが想定されます。たとえば、単一サイトによってしか書き込まれていないハッシュや、 異常な頻度で要求されるハッシュです。そして、公称上の PHL ステータスに関係なく、そのようなパターンをプロービング試行として扱うことが想定されます。
8. 他の仕様との統合
この節は非規範的です。
ここで定義されるCOS レジストリには、
requestFileHandle()
を直接経由することなく、4つのホスト統合からもアクセスできる。それぞれの
統合は、この文書ではなく、それぞれのホスト仕様で定義される。この
仕様では、それらの統合が基盤として使用することが期待される共通の基礎概念(COS ハッシュ、COS エントリ、
可用性ゲーティング、および公開ハッシュリスト)のみを定義する。
-
HTML: すでに
integrity[SRI] を持つlinkおよびscript要素上のcrossoriginstorage属性。WHATWG に whatwg/html#12770 で提案されている。 -
JavaScript:
integrityと併用できる、ホスト定義のcrossOriginStorageimport 属性。Import Attributes 提案を基盤とし、WHATWG に whatwg/html#12771 で提案されている。 -
CSS:
integrity()と併用できるcross-origin-storage()<request-url-modifier>。 CSS Working Group に w3c/csswg-drafts#14056 で提案されている。 -
Fetch:
integrity[FETCH] と併用できる、crossOriginStorageRequestInitオプション。WHATWG に whatwg/fetch#1954 で提案されている。 3つの宣言的形式とは異なり、これにはホスト定義の destination がないため、 COS レジストリから提供されるResponseが MIME タイプ、ステータス、およびその他のメタデータをどのように報告するかは、 その仕様にとって未解決の問題である。COS エントリはバイトのみを保存する。
説明のためだけに、同じグローバルに共有されるリソースを、4つの各形式を通じて クロスオリジンストレージにオプトインする例を以下に示す:
< script src = "popular-library.js" integrity = "sha256-abc123..." crossoriginstorage = "*" ></ script >
import datafrom "popular-resource.ext" with { integrity: "sha256-abc123..." , crossOriginStorage: "*" , };
@font-face { font-family : "Popular Font" ; src : url ( "popular-font.woff2" integrity("sha256-abc123..." ) cross-origin-storage ( *)); }
const response= await fetch( "popular-resource.ext" , { integrity: "sha256-abc123..." , crossOriginStorage: "*" , });
これらのスニペットは説明のためだけのものである。この構文はいずれもこの仕様では定義されておらず、
制限された非 "*" の origins 値をどのように表記するかを含め、各形式の正式な文法は、
この文書ではなく、それぞれのホスト仕様に属する。表記は意図的に
異なっている。RequestInit メンバーは sequence<DOMString> を取ることができ、
origins
と完全に一致する一方、属性値、
import 属性値、および CSS modifier 引数が保持できるのはテキストだけである。
4つの形式すべては、ネットワーク取得にフォールバックする前に、まず一致し、開示可能なエントリがあるか
COS レジストリを参照し、
正常に取得され完全性が検証されたリソースを、他のオリジンによる再利用のため
COS レジストリに保存するという処理モデルを共有することが期待される。
これは requestFileHandle()
が行うこととまったく同じである。
これらの統合に関する議論は、このリポジトリの issue tracker ではなく、それらを採用する
ホスト仕様の tracker で行われるべきである。
謝辞
Tab Atkins-Bittner、Yash Raj Bharti、Joshua Lochner からの貴重なフィードバック、 および Kenji Baheux と Kevin Moore からの貴重な着想またはアイデアに深く感謝します。
この仕様には、 ファイルシステムをモデルとした内容が含まれます。同仕様は W3C ソフトウェア および文書ライセンスの下で利用できます。