1. はじめに
ウェブ上のサイトやアプリケーションは、単一オリジンのリソースだけで構成されることはほとんどありません。例えば、著者は様々なサービスやコンテンツ配信ネットワーク(CDN)からスクリプトやスタイルを取得し、配信された内容が本当に期待したものかを信頼する必要があります。攻撃者がユーザーを悪意あるサーバーからコンテンツをダウンロードさせるよう誘導した場合(DNS [RFC1035]ポイズニングなど)、著者には対処手段がありません。同様に、攻撃者がCDNサーバー上のファイルを置き換えることができれば、任意のコンテンツを注入することも可能です。
安全なチャネルを通じてリソースを配信することで、このリスクの一部は軽減できます。TLS [TLS]、HSTS [RFC6797]、公開鍵ピンニング[RFC7469]によって、ユーザーエージェントは本当に意図したサーバーと通信していることをかなり確信できます。しかし、これらの仕組みはサーバーのみを認証し、コンテンツ自体は認証しません。サーバーへのアクセス権を持つ攻撃者(や管理者)は、自由にコンテンツを改ざんできます。理想的には、著者がサーバーの鍵だけでなくコンテンツもピン留めできれば、リソースの正確な内容だけが読み込まれ、実行されることを保証できます。
本書はそのような検証方式を定義し、2つのHTML要素にintegrity
属性を拡張します。この属性には、著者が期待するリソースの内容の暗号学的ハッシュ値を格納します。例えば、著者がフレームワークを自身のオリジンではなく共有サーバーから読み込む場合、https://example.com/example-framework.js
の期待されるSHA-384ハッシュ値がLi9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7
であると指定すれば、ユーザーエージェントはそのURLから取得したデータが期待したハッシュ値と一致しているかを検証した上で、JavaScriptを実行します。この整合性検証により、攻撃者が悪意あるコンテンツを差し替えるリスクを大幅に低減できます。
この例は、script
要素にハッシュ値を追加することでユーザーエージェントに伝達できます:
< script src = "https://example.com/example-framework.js" integrity = "sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7" crossorigin = "anonymous" ></ script >
もちろん、スクリプトだけでなく他のレスポンスタイプも整合性検証の恩恵を受けます。本仕様の方式はlink
要素にも適用され、今後のバージョンでは対象範囲が拡張される可能性があります。
1.1. 目的
-
サードパーティサービスが侵害された場合でも、そのスクリプトを含むすべてのサイトが自動的に侵害されないようにすべきです。コンテンツ著者は、読み込むコンテンツの期待値を指定する仕組みを持つことで、特定のスクリプトのみを読み込み、同じURLの任意のスクリプトを読み込まないようにできます。
-
検証機構は、無効なレスポンスを受信した場合に著者へ通知するエラー報告機能を備えるべきです。
1.2. ユースケース・例
1.2.1. リソース整合性
-
著者はグローバルに分散したユーザーのため、コンテンツ配信ネットワーク(CDN)を利用してパフォーマンス向上を図りたいと考えています。しかし、CDNのサーバーが著者が期待するコードのみを配信することを保証する必要があります。CDNの侵害や予期せぬ悪意ある挙動によるサイトの改ざんリスクを軽減するため、ページに含める
link
要素に整合性メタデータを追加します: -
著者は、サードパーティのアナリティクスサービスが提供するJavaScriptをページに含めたいと考えています。慎重にレビューしたコードのみが実行されるよう保証するため、著者はスクリプトの整合性メタデータを生成し、
script
要素に追加します: -
ユーザーエージェントは、高権限のHTMLコンテキスト(例: ブラウザの新しいタブページ)で実行されるJavaScriptコードが表示前に改ざんされないよう保証したいと考えています。整合性メタデータは、これら高権限コンテキストで改ざんされたJavaScriptが実行されるリスクを軽減します。
2. 主要概念と用語
このセクションでは文書全体で使用されるいくつかの用語を定義します。
ダイジェストとは、任意のデータブロックに対して暗号学的ハッシュ関数を実行した結果をbase64でエンコードしたものを指します。
オリジンおよび同一オリジンの用語はHTMLで定義されています。[HTML]
base64エンコーディングはRFC 4648のセクション4で定義されています。[RFC4648]
SHA-256、SHA-384、SHA-512は、NISTが定義するSHA-2暗号学的ハッシュ関数群の一部です。[SHA2]
有効なSRIハッシュアルゴリズムトークン集合は、順序付き集合«
"sha256
", "sha384
", "sha512
" »(それぞれSHA-256、SHA-384、SHA-512に対応)。この集合の順序は意味を持ち、より強力なアルゴリズムが後ろに並びます。詳細は§ 3.2.2
優先順位および§ 3.3.3 集合から最強のメタデータを取得を参照してください。
文字列が有効なSRIハッシュアルゴリズムトークンであるとは、そのASCII小文字化が含まれている場合、有効なSRIハッシュアルゴリズムトークン集合に含まれることを指します。
2.1. 文法上の概念
この文書で使用される拡張バッカス・ナウア形式(ABNF)記法はRFC5234で定義されています。[ABNF]
RFC5234の付録B.1は、VCHAR(表示可能文字)およびWSP(空白)の規則を定義しています。
Content Security Policyはbase64-value
およびhash-algorithm
規則を定義しています。[CSP]
3. フレームワーク
ここで規定される整合性検証機構は、リソースに対して十分に強力な暗号学的ダイジェストを生成し、そのダイジェストをユーザーエージェントに送信してレスポンスの検証に利用するというプロセスに集約されます。
3.1. 整合性メタデータ
レスポンスの整合性を検証するためには、ユーザーエージェントは整合性メタデータをリクエストの一部として必要とします。このメタデータは以下の情報で構成されます:
-
暗号学的ハッシュ関数("alg")
-
ダイジェスト("val")
-
オプション("opt")
レスポンスの整合性検証には、ハッシュ関数とダイジェストの指定が必須です。
注: 現時点ではオプションは定義されていませんが、将来的な仕様バージョンでMIMEタイプなどのオプションが定義される可能性があります。[MIME-TYPES]
このメタデータは、Content Security Policy Level 2仕様のセクション4.2にあるhash-source
(シングルクォートを除く)と同じ形式でエンコードしなければなりません。
例えば、スクリプトリソースがalert('Hello, world.');
という文字列のみを含む場合、著者はハッシュ関数としてSHA-384を選択できます。H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO
が生成されるbase64エンコードされたダイジェストです。これを次のようにエンコードします:
echo -n"alert('Hello, world.');" | openssl dgst -sha384 -binary| openssl base64 -A
3.2. 暗号学的ハッシュ関数
適合するユーザーエージェントは、リクエストの整合性メタデータの一部としてSHA-256、SHA-384、SHA-512暗号学的ハッシュ関数をサポートしなければならず、将来の仕様で定義される追加のハッシュ関数もサポートしてもよいです。
注: 本書でサポートされるアルゴリズムは現時点では第二原像攻撃や衝突攻撃に対して安全と考えられています。将来サポートされるアルゴリズムの追加・削除時も同様の基準を適用することが望ましいです。詳細は§ 5.2 ハッシュ衝突攻撃を参照してください。
3.2.1. 柔軟性
将来的な暗号学的発見に対応する柔軟性を持たせるため、単一リソースに複数セットの整合性メタデータを関連付けることができます。例えば、前節のリソースは以下のいずれかのハッシュ式で表現できます:
sha384-H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO sha512-Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw==
著者は例えば両方を指定することもできます:
< script src = "hello_world.js" integrity = "sha384-H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO sha512-Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw==" crossorigin = "anonymous" ></ script >
この場合、ユーザーエージェントはリスト中で最も強力なハッシュ関数を選択し、そのメタデータでレスポンスを検証します(§ 3.3.2 メタデータの解析および§ 3.3.3 集合から最強のメタデータを取得のアルゴリズム参照)。
ハッシュ関数が安全でないと判断された場合、ユーザーエージェントはそのハッシュ関数による整合性検証のサポートを非推奨とし、最終的に削除すべきです。ユーザーエージェントは非推奨関数によるダイジェストでレスポンスの妥当性をチェックしてもかまいません。
著者が古いユーザーエージェントに縛られず強力なハッシュ関数へ切り替えられるよう、サポートされていないハッシュ関数による検証は整合性値が未指定の場合と同様に扱われます(§ 3.3.4 bytesがmetadataListに一致するか?参照)。著者は強力なハッシュ関数の利用を推奨され、利用可能になったら随時移行を開始してください。
3.2.2. 優先順位
ハッシュアルゴリズムの優先順位は、有効なSRIハッシュアルゴリズムトークン集合におけるトークンの順序で指定されます。集合の前方のアルゴリズムほど弱く、後方ほど強力です。
現行仕様では、SHA-256はSHA-384より弱く、SHA-512が最も強力です。他のハッシュアルゴリズムは本仕様ではサポートされていません。
3.3. レスポンス検証アルゴリズム
3.3.1. algorithmをbytesへ適用
-
resultを、algorithmをbytesに適用した結果とする。
-
resultをbase64エンコードした結果を返す。
3.3.2. メタデータの解析
文字列metadataが与えられたとき、メタデータを解析するには以下の手順を実行します:
注: このアルゴリズムは、ユーザーエージェントが理解できるハッシュ関数のハッシュ式集合を返します。
-
resultを空集合とする。
-
スペースでmetadataを分割して得られる各itemについて:
-
expression-and-optionsを、itemをU+003F(?)で分割した結果とする。
-
algorithm-expressionをexpression-and-options[0]とする。
-
base64-valueを空文字列とする。
-
algorithm-and-valueを、algorithm-expressionをU+002D(-)で分割した結果とする。
-
algorithmをalgorithm-and-value[0]とする。
-
もしalgorithmが有効なSRIハッシュアルゴリズムトークンでなければ、continueする。
-
もしalgorithm-and-value[1]が存在すれば、base64-valueをalgorithm-and-value[1]に設定する。
-
metadataを、順序付きマップ«["alg" → algorithm, "val" → base64-value]»とする。
注: オプションは定義されていないため(§ 3.1 整合性メタデータ参照)、対応するエントリはmetadataに設定しません。将来バージョンでオプションが定義された場合、expression-and-options[1]を
options
として利用できます。
-
-
resultを返す。
3.3.3. setから最強のメタデータを取得
-
resultを空集合、strongestをnullとする。
-
setの各itemについて:
-
保証:item["
alg
"]は有効なSRIハッシュアルゴリズムトークンである。 -
もしresultが空集合なら:
-
currentAlgorithmをstrongest["
alg
"]、currentAlgorithmIndexを有効なSRIハッシュアルゴリズムトークン集合におけるcurrentAlgorithmのインデックスとする。 -
newAlgorithmをitem["
alg
"]、newAlgorithmIndexを有効なSRIハッシュアルゴリズムトークン集合におけるnewAlgorithmのインデックスとする。 -
もしnewAlgorithmIndexがcurrentAlgorithmIndexより小さければ、続行。
-
それ以外で、newAlgorithmIndexがcurrentAlgorithmIndexより大きい場合:
-
strongestをitemに設定。
-
resultを« item »に設定。
-
-
それ以外の場合、newAlgorithmIndexとcurrentAlgorithmIndexが同じ値なら、resultにitemを追加。
-
-
resultを返す。
3.3.4. bytesがmetadataListに一致するか?
-
parsedMetadataを、metadataListを解析した結果とする。
-
もしparsedMetadataが空集合なら、
true
を返す。 -
metadataをparsedMetadataから最強のメタデータを取得した結果とする。
-
metadataの各itemについて:
-
algorithmをitem["alg"]とする。
-
expectedValueをitem["val"]とする。
-
actualValueをalgorithmをbytesへ適用した結果とする。
-
もしactualValueがexpectedValueと厳密一致した場合、
true
を返す。
-
-
false
を返す。
このアルゴリズムにより、ユーザーエージェントは複数の有効かつ強力なハッシュ関数を受理できます。例えば、開発者は次のようなscript
要素を書くことができます:
< script src = "https://example.com/example-framework.js" integrity = "sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7 sha384-+/M6kredJcxdsqkczBUjMLvqyHb1K/JThDXWsBVxMEeZHEaMKEOEct339VItX1zB" crossorigin = "anonymous" ></ script >
この場合、ユーザーエージェントは2つの異なるコンテンツペイロードのいずれかを受理できます。1つは1つ目のSHA-384ハッシュ値と一致し、もう1つは2つ目のSHA-384ハッシュ値と一致します。
注: ユーザーエージェントはユーザーの設定、ブックマークレット、サードパーティ追加機能などでこのアルゴリズムの結果を変更できる場合があります。例えばHTTPS Everywhereのような拡張によるリダイレクトでも、リソースのHTTPS版とHTTP版が異なっていても、正常に読み込み・実行されることがあります。
注: サブリソース整合性にはCORSが必要です。CORSなしで利用しようとすると論理エラーとなるため、ユーザーエージェントは開発者コンソールで警告メッセージを報告することが推奨されます。[Fetch]
3.4. HTML文書サブリソースの検証
さまざまなHTML要素は、ドキュメントへ埋め込まれたり、その文脈で実行されたりするリソースへのリクエストを生成します。これらの一部要素で整合性メタデータをサポートするため、link
およびscript
要素のコンテンツ属性リストに新たにintegrity
属性が追加されます。[HTML]
注:
本仕様の将来バージョンでは、a
、audio
、embed
、iframe
、img
、link
、object
、script
、source
、track
、video
など、全てのサブリソース要素で整合性サポートが追加される可能性があります。
3.5. integrity
属性
integrity
属性は、要素の整合性メタデータを表します。
この属性値は空文字列、または下記ABNF文法で記述される有効なメタデータが1つ以上でなければなりません:
integrity-metadata = *WSP hash-with-options *(1*WSP hash-with-options ) *WSP / *WSP hash-with-options = hash-expression *("?" option-expression) option-expression = *VCHAR hash-expression = hash-algorithm "-" base64-value
option-expression
は各hash-expression
ごとに関連付けられ、その直前のhash-expression
のみに適用されます。
ユーザーエージェントが将来のオプションと完全な前方互換性を維持するため、認識できないoption-expression
はすべて無視しなければなりません。
注:
option-expression
は構文上予約されているものの、現時点ではオプションは定義されていません。将来の仕様バージョンではより具体的なオプション構文が定義される可能性が高いため、現段階ではできるだけ広く定義されています。
3.6.
integrity
リンク処理オプション
整合性メタデータは
`link
`
HTTPレスポンスヘッダーにも、integrity
リンクパラメータとして指定できます。この場合も要素のintegrity
属性と同じintegrity-metadata
文法で指定しなければなりません。例:
Link: </style.css>; rel=preload; as=style; crossorigin="anonymous"; integrity="sha256-[digest goes here]"
3.7. 整合性違反の取り扱い
ユーザーエージェントは整合性チェックに失敗したレスポンスの描画や実行を拒否し、代わりにFetchで定義されるネットワークエラーを返します。[Fetch]
注:
整合性チェックに失敗した場合、error
イベントが発火します。開発者がCDNではなくセカンダリの信頼できるが遅いソース等、標準的なフォールバックリソースを提供したい場合、このerror
イベントをキャッチし、失敗したリソースを適切な別リソースで置換するハンドラを用意できます。
3.8. Integrity-Policy
Integrity-Policy
およびIntegrity-Policy-Report-Only
HTTPヘッダーは、ドキュメントが読み込む特定のdestinationのサブリソースすべてに対する整合性メタデータ要件のポリシーを強制できます。
ヘッダー値は辞書型で、各メンバー値は内部リストであり、トークンのリストです。[RFC9651]
sourceは文字列で、値は"inline
"のみです。
destinationはdestination typeであり、値は"script
"と"style
"です。
整合性ポリシーは、以下を含む構造体です:
-
sources:sourceのリスト(初期値は空)。
-
blocked destinations:destinationのリスト(初期値は空)。
-
endpoints:文字列のリスト(初期値は空)。
整合性ポリシーの処理は、header list headersとheader name headerNameで以下のように行う:
-
integrityPolicyを新しい整合性ポリシーとする。
-
dictionaryを、構造化フィールド値を取得した結果とする(headers、headerName、"
dictionary
"を与える)。 -
もしdictionary["
sources
"]が存在しないか、その値が"inline"を含む場合は、integrityPolicyのsourcesに"inline
"を追加。 -
もしdictionary["
blocked-destinations
"]が存在するなら:-
その値が"
script
"を含むなら、integrityPolicyのblocked destinationsに"script
"を追加。 -
その値が"
style
"を含むなら、integrityPolicyのblocked destinationsに"style
"を追加。
-
-
もしdictionary["
endpoints
"]が存在するなら:-
integrityPolicyのendpointsをdictionary['endpoints']に設定。
-
-
integrityPolicyを返す。
Integrity-Policy: blocked-destinations=(script), endpoints=(integrity-endpoint)
このブロックにより、"integrity-endpoint
"レポートエンドポイント(対応するReporting-Endpoints
ヘッダーで定義)にレポートも発行されます。
開発者は"integrity-violation
"のReportingObserverを登録することで、JavaScriptでレポートを取得することもできます。
3.8.1. Integrity-Policyヘッダーの解析
Integrity-Policyヘッダーを解析するには、Response response およびpolicy container containerが与えられたとき、以下を行う:-
headersをresponseのヘッダーリストとする。
-
もしheadersがintegrity-policyを含むなら、 containerのintegrity policyを 対応する整合性ポリシーの処理の結果に設定する。 (対応するヘッダー値を使用)
-
もしheadersがintegrity-policy-report-onlyを含むなら、 containerのreport only integrity policyを 対応する整合性ポリシーの処理の結果に設定する。 (対応するヘッダー値を使用)
3.8.2. Integrity Policyによるリクエストのブロック可否
Integrity Policyによるリクエストのブロック可否を判定するには、 request requestが与えられたとき、以下を行う:-
policyContainerをrequestのpolicy containerとする。
-
parsedMetadataをparse metadataに requestのintegrity metadataを渡して得られる結果とする。
-
もしparsedMetadataが空集合ではなく、かつrequestのmodeが"
cors
"または"same-origin
"なら、 "Allowed"を返す。 -
policyをpolicyContainerのintegrity policyとする。
-
reportPolicyをpolicyContainerのreport only integrity policy とする。
-
もしpolicyとreportPolicyが両方とも空の整合性ポリシーなら、"Allowed"を返す。
-
globalをrequestのclientのglobal objectとする。
-
もしglobalが
Window
でもWorkerGlobalScope
でもなければ、"Allowed
"を返す。 -
blockをboolean型で初期値falseとする。
-
reportBlockをboolean型で初期値falseとする。
-
もしpolicyのsourcesが"inline"を含み、 かつpolicyのblocked destinationsがrequestのdestinationを含むなら、 blockをtrueに設定する。
-
もしreportPolicyのsourcesが"inline"を含み、 かつreportPolicyのblocked destinationsがrequestのdestinationを含むなら、 reportBlockをtrueに設定する。
-
もしblockまたはreportBlockがtrueなら、違反を報告を request, block, reportBlock, policy, reportPolicyで呼び出す。
-
もしblockがtrueなら"
Blocked
"を返し、そうでなければ"Allowed
"を返す。
3.8.3. 違反の報告
dictionary :
IntegrityViolationReportBody ReportBody {USVString ;
documentURL USVString ;
blockedURL USVString ;
destination boolean ; };
reportOnly
違反を報告するには、 Request request、boolean block、 boolean reportBlock、整合性ポリシー policy、 および整合性ポリシー reportPolicyが与えられたとき、以下を行う:
-
settingsObjectをrequestのclientとする。
-
globalをsettingsObjectのglobal objectとする。
-
保証:globalは
Window
またはWorkerGlobalScope
である。 -
urlをnullとする。
-
もしglobalが
Window
なら、 urlをglobalの関連付けられたDocumentのURL
に設定。 -
もしglobalが
WorkerGlobalScope
なら、 urlをglobalのURLに設定。 -
documentURLをurlをレポート用にストリップした結果とする。
-
blockedURLを、requestのURLにレポート用URLストリップを適用した結果とする。
-
もしblockがtrueなら、policyのendpointsの各endpointについて:
-
bodyを新しい
IntegrityViolationReportBody
として、以下で初期化:documentURL
-
documentURL
blockedURL
-
blockedURL
destination
-
requestのdestination
reportOnly
-
false
-
レポート生成とキューイングを以下の引数で呼び出す:
- context
-
settingsObject
- type
-
"
integrity-violation
" - destination
-
endpoint
- data
-
body
-
-
もしreportBlockがtrueなら、reportPolicyのendpointsの各endpointについて:
-
reportBodyを新しい
IntegrityViolationReportBody
として、以下で初期化:documentURL
-
documentURL
blockedURL
-
blockedURL
destination
-
requestのdestination
reportOnly
-
true
-
レポート生成とキューイングを以下の引数で呼び出す:
- context
-
settingsObject
- type
-
"
integrity-violation
" - destination
-
endpoint
- data
-
reportBody
-
4. プロキシ
最適化プロキシやレスポンスを変更するその他の中間サーバーは、これらのレスポンスに関連付けられたダイジェストが新しいコンテンツと同期していることを必ず保証しなければなりません。1つの選択肢は、リソースに関連付けられた整合性メタデータを更新することです。もう1つは、ページ著者が整合性検証を要求したリソースの正規バージョンのみを配信することです。
中間サーバーへの通知を支援するため、リソースを配信するサーバーは、リソースとともにCache-Control
ヘッダーを値no-transform
で送信するべきです。
5. セキュリティおよびプライバシーの考慮事項
このセクションは規範的ではありません。
5.1. 非セキュアなコンテキストは非セキュアなまま
整合性メタデータ がHTTPページなどのセキュアコンテキスト以外のコンテキストから配信された場合、外部リソースがホストされているサーバーの侵害のみからオリジンを保護します。ネットワーク攻撃者はダイジェストを途中で改変したり(あるいは完全に削除したり、その他文書に対し何でも)でき、ハッシュで検証しようとするレスポンス自体も改変可能です。そのため、著者はセキュアコンテキストでのみ整合性メタデータを配信することを推奨します。関連:Securing the Web
5.2. ハッシュ衝突攻撃
ダイジェストの強度は、それを生成したハッシュ関数に依存します。ユーザーエージェントは、既知の弱いハッシュ関数のサポートを拒否し、衝突耐性があると知られているアルゴリズムのみをサポートするべきです。推奨されないハッシュ関数の例にはMD5やSHA-1があります。執筆時点ではSHA-384が良い基準です。
さらに、ユーザーエージェントはサポートするハッシュ関数を定期的に再評価し、安全性が失われた関数はサポートを非推奨にすべきです。時間の経過とともにハッシュ関数が予想以上に弱いと判明したり、場合によっては破られることもあるため、ユーザーエージェントはこうした進展に常に注意を払う必要があります。
5.3. クロスオリジンのデータ漏洩
この仕様では、整合性保護されたクロスオリジンリクエストにリソースの内容が明示的にリクエスト元と共有されるようCORSプロトコルの使用を要求します。これが省略されると、攻撃者は同一オリジンポリシーを破り、クロスオリジンリソースに特定の内容があるかどうか知ることができます。
攻撃者は既知のダイジェストでリソースをロードし、ロード失敗を監視します。ロードが失敗すれば、レスポンスがハッシュと一致しなかったと推測でき、内容をある程度把握できます。例えば、ユーザーが特定サービスにログインしているか否かが分かる場合もあります。
さらに、攻撃者は静的なリソース内の特定値を総当たりで推測できます。例えば次のようなJSONレスポンスの場合:
攻撃者は様々な一般的ユーザー名でレスポンスのハッシュを事前計算し、それらを指定して文書ロードを繰り返します。ロードが成功すれば、攻撃者はユーザー名を正しく推測できたことになります。
6. 謝辞
ここに記載の多くの内容は、Gervase Markham氏のLink Fingerprints 構想およびWHATWGのLink Hashesに強く影響を受けています。
この仕様の初期バージョンに多大な貢献をしてくれたMike West氏に特別な感謝を捧げます。Brad Hill氏、Anne van Kesteren氏、Jonathan Kingston氏、Fatih Kilic氏、Mark Nottingham氏、Sergey Shekyan氏、Dan Veditz氏、Eduardo Vela氏、 Tanvi Vyas氏、Yoav Weiss氏、Michal Zalewski氏にも貴重なフィードバックをいただき感謝します。