Reporting API を使用して、セキュリティ違反や非推奨の API 呼び出しなどをモニタリングできます。
一部のエラーは本番環境でのみ発生します。ローカルや会議の参加者には表示されません。 実際のユーザー、実際のネットワーク、実際のデバイスによる開発 変えることです。Reporting API を使用すると、このようなエラーの一部、たとえば セキュリティ違反、またはサポート終了予定の API の呼び出しをエンドポイントに送信し、 あります。
HTTP ヘッダーを介してモニタリングする対象を宣言できます。 ブラウザによって操作されます。
Reporting API を設定すると、ユーザーが 修正できます
この投稿では、この API の機能と使用方法について説明します。それでは詳しく見ていきましょう。
デモとコード
Reporting API の実際の動作を確認する Chrome 96 以降(Chrome 。
概要
<ph type="x-smartling-placeholder">![レポートの生成からデベロッパーによるレポートへのアクセスまで、以下の手順をまとめた図](https://developer.chrome.com/static/docs/capabilities/web-apis/reporting-api/image/diagram-summarizing-step-7115c265c2e02.png?hl=ja)
たとえば、サイト site.example
に Content-Security-Policy と Document-Policy があるとします。機能がわからない場合は、引き続き
この例を理解できます
ポリシー違反のタイミングを知るため、サイトを監視することにしましたが、 コードベースで使用されている可能性がある、非推奨の API または非推奨になる予定の API に注意する必要があります。
これを行うには、Reporting-Endpoints
ヘッダーを構成し、これらのエンドポイントをマッピングします。
必要に応じて、ポリシーの report-to
ディレクティブを使用して名前を指定できます。
Reporting-Endpoints: main-endpoint="https://reports.example/main", default="https://reports.example/default"
# Content-Security-Policy violations and Document-Policy violations
# will be sent to main-endpoint
Content-Security-Policy: script-src 'self'; object-src 'none'; report-to main-endpoint;
Document-Policy: document-write=?0; report-to=main-endpoint;
# Deprecation reports don't need an explicit endpoint because
# these reports are always sent to the `default` endpoint
不測の事態が発生し、一部のお客様がこれらのポリシーに違反しています。 できます。
違反の例
index.html
<script src="script.js"></script>
<!-- CSP VIOLATION: Try to load a script that's forbidden as per the Content-Security-Policy -->
<script src="https://example.com/script.js"></script>
script.js
、index.html
が読み込みました
// DOCUMENT-POLICY VIOLATION: Attempt to use document.write despite the document policy
try {
document.write('<h1>hi</h1>');
} catch (e) {
console.log(e);
}
// DEPRECATION: Call a deprecated API
const webkitStorageInfo = window.webkitStorageInfo;
ブラウザで CSP 違反レポート、ドキュメント ポリシー違反レポート、非推奨化レポートが生成される 報告します
最大で 1 分後に、ブラウザはレポートを この違反タイプ用に構成されたエンドポイントです。レポートは 帯域外 (サーバーやサイトではなく)ブラウザそのものです。
エンドポイントはこれらのレポートを受信します。
これで、これらのエンドポイントのレポートにアクセスして、何が問題なのかをモニタリングできるようになりました。 ユーザーに影響している問題のトラブルシューティングを開始する準備が整いました。
サンプル レポート
{
"age": 2,
"body": {
"blockedURL": "https://site2.example/script.js",
"disposition": "enforce",
"documentURL": "https://site.example",
"effectiveDirective": "script-src-elem",
"originalPolicy": "script-src 'self'; object-src 'none'; report-to main-endpoint;",
"referrer": "https://site.example",
"sample": "",
"statusCode": 200
},
"type": "csp-violation",
"url": "https://site.example",
"user_agent": "Mozilla/5.0... Chrome/92.0.4504.0"
}
ユースケースとレポートの種類
Reporting API は、さまざまな種類の興味深い警告や問題をモニタリングできるように構成できます。 サイト全体で発生しているイベントを特定します
レポートの種類 | レポートが生成される状況の例 |
---|---|
CSP 違反(レベル 3 のみ) | Content-Security-Policy (CSP)が設定されているページのいずれかに、CSP で許可されていないスクリプトを読み込もうとしています。 |
COOP 違反 | ページに Cross-Origin-Opener-Policy が設定されていますが、クロスオリジン ウィンドウがドキュメントを直接操作しようとしています。 |
COEP 違反 | ページには Cross-Origin-Embedder-Policy が設定されていますが、ドキュメントにはクロスオリジン ドキュメントによる読み込みが有効になっていないクロスオリジン iframe が含まれています。 |
ドキュメントのポリシー違反 | ページに document.write の使用を禁止するドキュメント ポリシーがありますが、スクリプトが document.write を呼び出そうとしています。 |
権限ポリシーへの違反 | このページには、マイクの使用を禁止する権限ポリシーと、音声入力を要求するスクリプトがあります。 |
非推奨に関する警告 | 非推奨になった API または今後使用が予定されている API をページで使用しています。直接、または最上位のサードパーティ スクリプトを介して呼び出すことができます。 |
介入 | このページが、セキュリティ、パフォーマンス、またはユーザー エクスペリエンス上の理由でブラウザが無視すると判断したことを行おうとしています。Chrome の例: ページで速度が遅いネットワークで document.write が使用されているか、ユーザーがまだ操作していないクロスオリジン フレームで navigator.vibrate が呼び出されています。 |
衝突事故 | サイトが開いている間にブラウザがクラッシュする。 |
レポート
レポートはどのように表示されますか?
ブラウザは、構成したエンドポイントにレポートを送信します。次のようなリクエストを送信します。
POST
Content-Type: application/reports+json
これらのリクエストのペイロードはレポートのリストです。
レポートのリストの例
[
{
"age": 420,
"body": {
"columnNumber": 12,
"disposition": "enforce",
"lineNumber": 11,
"message": "Document policy violation: document-write is not allowed in this document.",
"policyId": "document-write",
"sourceFile": "https://site.example/script.js"
},
"type": "document-policy-violation",
"url": "https://site.example/",
"user_agent": "Mozilla/5.0... Chrome/92.0.4504.0"
},
{
"age": 510,
"body": {
"blockedURL": "https://site.example/img.jpg",
"destination": "image",
"disposition": "enforce",
"type": "corp"
},
"type": "coep",
"url": "https://dummy.example/",
"user_agent": "Mozilla/5.0... Chrome/92.0.4504.0"
}
]
各レポートで確認できるデータは次のとおりです。
フィールド | 説明 |
---|---|
age |
レポートのタイムスタンプと現在の時刻の間のミリ秒数。 |
body |
JSON 文字列にシリアル化された実際のレポートデータ。レポートの body に含まれるフィールドは、レポートの type によって決まります。#️ レポートの種類によって本文は異なります。
各レポートタイプの正確な本文については、レポート エンドポイントのデモ を確認し、手順に沿ってサンプル レポートを生成します。 |
type |
レポートタイプ(例: csp-violation 、coep )。 |
url |
レポート生成元のドキュメントまたはワーカーのアドレス。ユーザー名、パスワード、フラグメントなどの機密データは、この URL から削除されます。 |
user_agent |
レポートの生成元となったリクエストの User-Agent ヘッダー。 |
クルデンシャル レポート
レポートを生成するページと同じオリジンのレポート エンドポイントが認証情報を受け取る (Cookie)が使用されます。
認証情報は、レポートに関する有用な追加コンテキストを提供する場合があります。 たとえば、特定のユーザーのアカウントでエラーが継続的にトリガーされているかどうか、特定のシーケンス 他のページで行われたアクションのうち、このページのレポートがトリガーされた割合。
ブラウザがレポートを送信するタイミングと方法
レポートはサイトから帯域外で配信される: ブラウザが 構成済みのエンドポイントに送信されますまた、通知を送信するタイミングを ブラウザがレポートを送信します。取り込み、キューに入れられ、 都合のよい時間を決定します。
つまり、Reporting API を使用する際にパフォーマンス上の問題はほとんど、あるいはまったくありません。
レポートを一括送信できるように、レポートは遅れて送信されます(最大で 1 分かかります)。 これにより、帯域幅を節約してユーザーのネットワーク接続(特に 確認しましょう優先度の高い処理でビジー状態となる場合は、ブラウザで配信が遅れることもあります。 または、ユーザーがそのときに使用しているネットワークが低速または混雑しているかどうかを確認します。
サードパーティとファースト パーティの問題
お客様のページで発生している違反やサポート終了により生成されたレポートが送信されます 構成したエンドポイントに送信します。これには、サードパーティのスクリプトによる違反も含まれます。 確認できます
ページに埋め込まれたクロスオリジン iframe で発生した違反やサポートの終了は、 報告されません(少なくともデフォルトでは報告されません)。iframe には独自の IP アドレスや サイト(ファーストパーティ)のレポート サービスに報告する。しかしこれは リダイレクトされます。また、ほとんどのレポートはページのポリシーに違反した場合にのみ生成されますが、 ページのポリシーと iframe のポリシーに違いがあることを確認します。
非推奨の例
<ph type="x-smartling-placeholder">![Reporting-Endpoints ヘッダーがページにセットアップされている場合: ページで実行されているサードパーティのスクリプトによって呼び出された非推奨の API が、エンドポイントに報告されます。ページに埋め込まれた iframe によって呼び出された非推奨の API は、エンドポイントに報告されません。サポート終了レポートは、iframe サーバーでレポート エンドポイントが設定されている場合にのみ生成され、このレポートは iframe サーバーで設定されたエンドポイントに送信されます。](https://developer.chrome.com/static/docs/capabilities/web-apis/reporting-api/image/if-reporting-endpoints-h-c4facaee3ba26.png?hl=ja)
ブラウザ サポート
以下の表は、Reporting API v1 に対するブラウザ サポートをまとめたものです。
Reporting-Endpoints
ヘッダー。Reporting API v0(Report-To
ヘッダー)のブラウザ サポートは、
レポートの種類が 1 つだけで、ネットワーク エラー ロギングは新しい Reporting API でサポートされていません。
詳しくは、移行ガイドをご覧ください。
レポートの種類 | Chrome | Chrome(iOS) | Safari | Firefox | Edge |
---|---|---|---|---|---|
CSP 違反(レベル 3 のみ)* | ✔ はい | ✔ はい | ✔ はい | ✘ できない | ✔ はい |
ネットワーク エラーのロギング | ✘ できない | ✘ できない | ✘ できない | ✘ できない | ✘ できない |
COOP/COEP 違反 | ✔ はい | ✘ できない | ✔ はい | ✘ できない | ✔ はい |
その他すべてのタイプ: ドキュメント ポリシー違反、非推奨、介入、クラッシュ | ✔ はい | ✘ できない | ✘ できない | ✘ できない | ✔ はい |
次の表は、新しい Reporting-Endpoints
ヘッダーを使用した report-to
のサポートをまとめたものです。Reporting-Endpoints
への移行をお考えの場合は、CSP レポートの移行に関するヒントをご覧ください。
Reporting API の使用
レポートの送信先を決定する
次のどちらかの方法でお問い合わせください。
- 既存のレポート コレクタ サービスにレポートを送信します。
- 自分で構築して運用するレポート コレクタにレポートを送信します。
オプション 1: 既存のレポート コレクタ サービスを使用する
レポート コレクタ サービスの例を以下に示します。
- report-uri
- URI ポート
他の解決策をご存じでしたら、問題を報告してお知らせください。この投稿を更新いたします。
レポート コレクターを選択する際は、価格だけでなく次の点も考慮してください。🧐?
- このコレクタはすべてのレポートタイプをサポートしていますか?たとえば、すべてのレポート エンドポイント ソリューションが COOP/COEP レポートをサポートしています
- アプリケーションの URL をサードパーティのレポート コレクタと共有しても問題ないでしょうか? ブラウザがこれらの URL から機密情報を削除したとしても、機密情報がこの方法で漏洩する可能性があります。リスクが高すぎるように思える場合や、 独自のレポート エンドポイントを運用できます。
オプション 2: 独自のレポート コレクタを構築して運用する
レポートを受け取る独自のサーバーを構築するのは簡単ではありません。手始めに、リソースをフォークして 記述できますExpress が組み込まれており、レポートの受信と表示が可能です。
ボイラープレート レポート コレクタにアクセスします。
[Remix to Edit] をクリックして、プロジェクトを編集可能にします。
これでクローンができました。目的に応じてカスタマイズできます。
ボイラープレートを使用せず、独自のサーバーをゼロから構築する場合:
Content-Type
がapplication/reports+json
のPOST
リクエストを確認して、レポートを認識します エンドポイントに送信されるリクエストの数を表します。- エンドポイントがサイトのオリジンと異なる場合は、CORS プリフライト リクエストをサポートしていることを確認します。
オプション 3: オプション 1 と 2 を組み合わせる
特定の種類のレポートについては特定のプロバイダに任せて、社内に ソリューションを提供しています
この場合は、次のように複数のエンドポイントを設定します。
Reporting-Endpoints: endpoint-1="https://reports-collector.example", endpoint-2="https://my-custom-endpoint.example"
Reporting-Endpoints
ヘッダーを構成する
Reporting-Endpoints
レスポンス ヘッダーを設定します。値は 1 つ、または一連のカンマで区切って指定する必要があります
Key-Value ペア:
Reporting-Endpoints: main-endpoint="https://reports.example/main", default="https://reports.example/default"
従来の Reporting API から新しい Reporting API に移行する場合は、
Reporting-Endpoints
と Report-To
の両方を設定する。詳しくは、移行ガイドをご覧ください。特に、100% の
report-uri
ディレクティブによる Content-Security-Policy
違反のみの場合は、CSP レポートの移行手順を確認してください。
Reporting-Endpoints: main-endpoint="https://reports.example/main", default="https://reports.example/default"
Report-To: ...
キー(エンドポイント名)
各キーは、main-endpoint
や endpoint-1
など、任意の名前にできます。
レポートごとに異なる名前付きエンドポイントを設定できます
(例: my-coop-endpoint
、my-csp-endpoint
)。これで、
では、タイプに応じて異なるエンドポイントにレポートをルーティングできます。
介入、非推奨、クラッシュなどを受ける場合
エンドポイントに default
を設定します。
Reporting-Endpoints
ヘッダーで default
エンドポイントが定義されていない場合、このタイプのレポートは送信されません(ただし、生成されます)。
値(URL)
各値は、レポートの送信先となる任意の URL です。URL ステップ 1 で決定した内容によります
エンドポイント URL:
- 先頭はスラッシュ(
/
)にします。相対パスはサポートされていません。 - クロスオリジン可その場合、認証情報はレポートとともに送信されません。
例
Reporting-Endpoints: my-coop-endpoint="https://reports.example/coop", my-csp-endpoint="https://reports.example/csp", default="https://reports.example/default"
その後、適切なポリシーでそれぞれの名前付きエンドポイントを使用するか、 単一のエンドポイントで保護できます。
ヘッダーを設定する場所
新しい Reporting API では、
投稿 - レポートの対象範囲はドキュメントです。つまり、ある特定の 1 つの
異なるドキュメント(site.example/page1
や
site.example/page2
は、さまざまなエンドポイントにレポートを送信できます。
サイトの任意のページで違反やサポート終了に関するレポートは、 すべてのレスポンスでヘッダーをミドルウェアとして設定します。
Express の例を次に示します。
const REPORTING_ENDPOINT_BASE = 'https://report.example';
const REPORTING_ENDPOINT_MAIN = `${REPORTING_ENDPOINT_BASE}/main`;
const REPORTING_ENDPOINT_DEFAULT = `${REPORTING_ENDPOINT_BASE}/default`;
app.use(function (request, response, next) {
// Set up the Reporting API
response.set(
'Reporting-Endpoints',
`main-endpoint="${REPORTING_ENDPOINT_MAIN}", default="${REPORTING_ENDPOINT_DEFAULT}"`,
);
next();
});
ポリシーを編集する
Reporting-Endpoints
ヘッダーの構成が完了したため、report-to
を追加します。
ディレクティブを、違反を受信する各ポリシー ヘッダーに追加してください。
できます。report-to
の値は、名前を付けたエンドポイントのいずれかにする必要があります。
構成されます。
複数のポリシーに複数のエンドポイントを使用することも、異なるポリシーを使用する 簡単に管理できます。
非推奨、介入、クラッシュに report-to
は必要ありません。
できます。これらのレポートは、どのポリシーにもバインドされません。データが一定の期間のみ
default
エンドポイントが設定され、この default
エンドポイントに送信されます。
例
# Content-Security-Policy violations and Document-Policy violations
# will be sent to main-endpoint
Content-Security-Policy: script-src 'self'; object-src 'none'; report-to main-endpoint;
Document-Policy: document-write=?0;report-to=main-endpoint;
# Deprecation reports don't need an explicit endpoint because
# these reports are always sent to the default endpoint
コード例
Express を使用するノードサーバーの例を以下に示します。 まとめられています。このデモでは、 いくつかのレポートタイプに対してレポートを設定し、結果を表示します。
レポート設定をデバッグする
意図的にレポートを生成する
Reporting API を設定する際には、エラーの原因となる ポリシーに沿って、レポートが想定どおりに生成、送信されているかどうかを確認します。 ポリシー違反などの不正行為を行うコード例を確認する すべてのタイプのレポートを生成する方法については、デモをご覧ください。
時間を節約
レポートは遅れて送信される場合があり(約 1 分)、長時間かかる
おすすめします。🙂? 幸いなことに、Chrome でデバッグする場合は、このフラグを使用して
--short-reporting-delay
: 生成後すぐにレポートを受信できます。
ターミナルで次のコマンドを実行して、このフラグを有効にします。
YOUR_PATH/TO/EXECUTABLE/Chrome --short-reporting-delay
DevTools を使用する
Chrome で、DevTools を使用して、送信済みまたは送信予定のレポートを確認します。
2021 年 10 月現在、この機能は試験運用版です。使用する手順は次のとおりです。
- Chrome バージョン 96 以降を使用している(ブラウザで「
chrome://version
」と入力して確認できます) - Chrome の URL バーに「
chrome://flags/#enable-experimental-web-platform-features
」と入力するか貼り付けます。 - [有効] をクリックします。
- ブラウザを再起動する。
- Chrome DevTools を開きます。
- Chrome DevTools で [設定] を開きます。[テスト] で、[レポート API の有効化パネルを [Application] パネルで確認できます。
- DevTools を再読み込みします。
- ページを再読み込みします。DevTools が開いているページで生成されたレポートは、 Chrome DevTools に表示されます。[アプリケーション] パネルの [Reporting API] の下にあります。
![レポートを一覧表示する DevTools のスクリーンショット](https://developer.chrome.com/static/docs/capabilities/web-apis/reporting-api/image/screenshot-devtools-list-adb1aaa437b6b.png?hl=ja)
レポートのステータス
[ステータス] 列で、レポートが正常に送信されたかどうかを確認できます。
ステータス | 説明 |
---|---|
Success |
ブラウザがレポートを送信し、エンドポイントから成功コード(200 または別の成功レスポンス コード 2xx )のレスポンスが返されます。 |
Pending |
現在、ブラウザはレポートの送信を試行しています。 |
Queued |
レポートは生成されましたが、ブラウザは現在送信を試行していません。レポートは、次の 2 つのケースのいずれかで Queued として表示されます。
<ph type="x-smartling-placeholder">
|
MarkedForRemoval |
しばらく再試行した後(Queued )、ブラウザはレポートの送信を停止しました。まもなく、送信するレポートのリストから削除されます。 |
レポートは、正常に送信されたかどうかにかかわらず、しばらくすると削除されます。
トラブルシューティング
レポートが生成されないか、エンドポイントに想定どおりに送信されませんか? この問題を解決するためのヒントをいくつかご紹介します。
レポートが生成されない
DevTools に表示されるレポートが正しく生成されている。 必要なレポートがこのリストに表示されない場合:
- ポリシーで
report-to
を確認してください。これが誤って設定されると、 レポートが生成されなくなります。[ポリシーを編集] に移動して、 この問題を修正します。この問題をトラブルシューティングするもう一つの方法は、Chrome の DevTools コンソールを確認することです。 想定した違反に関するエラーがコンソールにポップアップ表示されます。これは、おそらく 確認します。 - DevTools で開かれているドキュメント用に生成されたレポートしか表示されないことに注意してください。
リストに表示されます。例: サイト
site1.example
に iframesite2.example
が埋め込まれている場合 レポートが生成された場合、そのレポートが DevTools に表示されるのは、 iframe を開き、そのウィンドウ用に DevTools を開きます。
レポートは生成されるが、送信または受信されない
DevTools にレポートが表示されているのに、エンドポイントがレポートを受信しない場合はどうすればよいですか?
- 遅延時間を短くするようにしてください。レポートが表示されない理由は まだ送信されていません。
Reporting-Endpoints
ヘッダーの構成を確認します。問題がある場合は 送信されません。DevTools では、レポートのステータスはQueued
(Pending
にジャンプし、配信試行時にすぐにQueued
に戻ることがあります) 表示されます。この原因としては、次のようなものが考えられます。エンドポイントが使用されていますが、構成されていません。例:
Document-Policy: document-write=?0;report-to=endpoint-1; Reporting-Endpoints: default="https://reports.example/default"
ドキュメントのポリシー違反レポートは endpoint-1
に送信する必要がありますが、このエンドポイント名が構成されていません
Reporting-Endpoints
。
default
エンドポイントがありません。一部のレポートタイプ(非推奨、介入など) レポートは、default
という名前のエンドポイントにのみ送信されます。詳しくは、Reporting-Endpoints ヘッダーを設定するをご覧ください。引用符の欠落など、ポリシー ヘッダーの構文に問題がないか確認します。詳細を表示。
エンドポイントが受信リクエストを処理できることを確認します。
エンドポイントが CORS プリフライト リクエストをサポートしていることを確認します。対応していない場合、レポートを受信できません。
エンドポイントの動作をテストします。そのためには、インフラストラクチャの エンドポイントに次のようなリクエストを送信することで、ブラウザをエミュレートできます。 ブラウザが何を送信するかを定義します。以下のコマンドを実行します。
curl --header "Content-Type: application/reports+json" \ --request POST \ --data '[{"age":420,"body":{"columnNumber":12,"disposition":"enforce","lineNumber":11,"message":"Document policy violation: document-write is not allowed in this document.","policyId":"document-write","sourceFile":"https://dummy.example/script.js"},"type":"document-policy-violation","url":"https://dummy.example/","user_agent":"xxx"},{"age":510,"body":{"blockedURL":"https://dummy.example/img.jpg","destination":"image","disposition":"enforce","type":"corp"},"type":"coep","url":"https://dummy.example/","user_agent":"xxx"}]' \ YOUR_ENDPOINT
エンドポイントから成功コード(
200
または別の成功レスポンス コード2xx
)が返されます。そうでない場合 検出できます。
関連するレポート作成メカニズム
レポート専用
-Report-Only
ポリシー ヘッダーと Reporting-Endpoints
は連携して動作します。
Reporting-Endpoints
で構成され、次の report-to
フィールドで指定されるエンドポイント
Content-Security-Policy
、
Cross-Origin-Embedder-Policy
および
Cross-Origin-Opener-Policy
は、これらのポリシーに違反するとレポートを受け取ります。
Reporting-Endpoints
で構成されたエンドポイントは、
report-to
フィールド
Content-Security-Policy-Report-Only
、
Cross-Origin-Embedder-Policy-Report-Only
および
Cross-Origin-Opener-Policy-Report-Only
を選択します。
これらのポリシーに違反すると、報告者に報告されます。
どちらの場合もレポートは送信されますが、-Report-Only
ヘッダーによって
ポリシー違反や実際にブロックされることはなく、
破損またはブロックされる可能性があるものの報告。
ReportingObserver
ReportingObserver
JavaScript API を使用すると、
クライアントサイドの警告を監視します
ReportingObserver
と Reporting-Endpoints
ヘッダーは、次のようなレポートを生成します。
見た目は同じですが、使用できるユースケースが若干異なります。
次の場合は ReportingObserver
を使用します。
- 非推奨やブラウザの介入のみをモニタリングする場合。
ReportingObserver
が非推奨などのクライアントサイドの警告を表示 ブラウザの介入がありますが、Reporting-Endpoints
とは異なり、 CSP または COOP/COEP 違反など、その他の種類のレポートをキャプチャします。 - こうした違反にはリアルタイムで対応する必要があります。
ReportingObserver
は 違反イベントにコールバックを追加できます。 - デバッグに役立つ追加情報をレポートに添付する コールバックを介して通信します。
もう一つの違いは、ReportingObserver
がクライアントサイドでのみ構成されていることです。
サーバーサイド ヘッダーを制御できず、
Reporting-Endpoints
を設定します。
関連情報
- Reporting API v0 から v1 への移行ガイド
- ReportingObserver
- 仕様: 以前の Reporting API(v0)
- 仕様: 新しい Reporting API(v1)
ヒーロー画像提供: Nine Koepfer / @enka80 スプラッシュを解除、編集しました。この記事のレビューと提案をしてくれた Ian Clelland、Eiji Kitamura、Miliica Mihajlija に感謝します。