API 間で一貫したユーザー アクティベーションを実現

Mustaq Ahmed
Joe Medley
Joe Medley

悪意のあるスクリプトがポップアップなどの機密性の高い API を悪用するのを防ぐには、 ブラウザは、ユーザー コンテンツを介してこれらの API へのアクセスを制御します。 支援しますユーザーのアクティベーションとは、以下に関するブラウジング セッションの状態を指します。 ユーザー アクションに結び付けられます。つまり、状態とは、通常、ユーザーが状態を失うか、 ユーザーが現在そのページを操作している、またはページ上で操作を完了したユーザー 負荷を軽減できます。「ユーザー ジェスチャー」は、同じ考え方に対してよく使われている用語ですが、誤解を招くおそれもあります。対象 たとえば、ユーザーがスワイプやフリックのジェスチャーを行ってもページはアクティブにならず、 スクリプトの観点からはユーザーの アクティベーションではありません

昨今の主要なブラウザでは、ユーザーの有効化の仕組みが大きく異なる アクティベーション ゲート型 API を制御します。Chrome での実装は、 トークンベースのモデルは複雑すぎて、一貫性のある 動作を調整する必要があります。たとえば、Chrome は API への不完全なアクセスを許可するため、 postMessage()setTimeout() 呼び出し。ユーザーアクティベーションは Promise のサポート XHRゲームパッド操作など。ただし、 昔からある虫です。

バージョン 72 の Chrome には User Activation v2 が付属しており、 アクティベーションの空き状況の確認が完了しました。これにより、 前述の不整合を解消し、 MessageChannels)を 開発に集中できますさらに新しい実装では 提案するソリューションのリファレンス実装を 新しい仕様 長い目で見れば、すべてのブラウザを統合することを目指しています。

ユーザー アクティベーション v2 の仕組み

新しい API は、window オブジェクトごとに 2 ビットのユーザー アクティベーション状態を維持します。 (フレーム階層内の過去のユーザーのアクティベーション状態を表すスティッキー ビット)。 (ユーザーのアクティベーションを確認したことのある))と現在の状態の一時的なビット (フレームが約 1 秒後にユーザーのアクティベーションを確認した場合)。スティッキー ビット 設定後のフレームの存続期間中にリセットされることはありません。一時的なビット ユーザー操作のたびに設定され、有効期限が切れるか、 またはアクティベーションを使用する API の呼び出しによって行うか (例: window.open())。

アクティベーション ベース型 API は、ユーザー アクティベーションに依存する別の API です。 方法これらの API 固有の動作は、新しい API によって変更されることはありません。例: window.open() が消費するため、有効化できるポップアップは 1 ユーザーにつき 1 つのみです 以前のようにユーザー アクティベーションを行えば、Navigator.prototype.vibrate() は フレーム(またはそのサブフレームのいずれか)がユーザー アクションを確認したことがある場合に有効である。 といった具合です

変更内容

  • User Activation v2 は、ユーザー アクティベーションの可視性の概念を形式化しました。 フレーム境界を越えます。特定のフレームに対するユーザー インタラクションは、 そのフレームが含まれているすべてのフレームを 含まれます。(Chrome 72 では、一時的な回避策として すべての同一オリジン フレームに対する可視性が向上します。この回避策は、 新しいテクノロジーを ユーザーのアクティベーションをサブフレームに明示的に渡す)。
  • 有効化の制限された API が有効化されたフレームから呼び出されても、 イベント ハンドラ コードの外部では、ユーザーが有効にしている限り、 ステータスが「アクティブ」(例: 有効期限が切れていない、または使用されていない)。使用前 アクティベーション v2 の場合は、無条件に失敗します。
  • 有効期限内の複数の未使用のユーザー操作が融合します 最後のインタラクションに対応する 1 つのアクティベーションに統合します。

アクティベーション ゲート型 API における整合性の例

ポップアップ ウィンドウ(window.open() を使用して開きます)の 2 つの例を示します。 User Activation v2 が、有効化ゲート型 API の動作を実現する仕組み 必要があります。

setTimeout() 通話のチェーン

この例では setTimeout() のデモをご覧ください。 click ハンドラが 1 秒以内にポップアップを開こうとすると、 コードがどのように「構成」されてもできます。User Activation v2 は、 そのため、以下の各イベント ハンドラでは、イベントに応じたポップアップが click(100 ミリ秒の遅延):

function popupAfter100ms() {
  setTimeout(callWindowOpen, 100);
}

function asyncPopupAfter100ms() {
  setTimeout(popupAfter100ms, 0);
}

someButton.addEventListener('click', popupAfter100ms);
someButton.addEventListener('click', asyncPopupAfter100ms);

ユーザー アクティベーション v2 がなければ、2 番目のイベント ハンドラはすべてのブラウザで失敗します。 検証できます。(最初のテストで 場合によります)。

クロスドメインの postMessage() 呼び出し

この例は、 postMessage() のデモをご覧ください。 クロスオリジン サブフレーム内の click ハンドラが 2 つのメッセージを直接送信するとします。 親フレームに追加してください親フレームは、起動時にポップアップを表示できるようにする必要があります。 次のいずれかのメールを受信します(両方は不可)。

// Parent frame code
window.addEventListener('message', e => {
  if (e.data === 'open_popup' && e.origin === child_origin)
    window.open('about:blank');
});

// Child frame code:
someButton.addEventListener('click', () => {
  parent.postMessage('hi_there', parent_origin);
  parent.postMessage('open_popup', parent_origin);
});

ユーザー アクティベーション v2 がない場合、親フレームは受信時にポップアップを開けません 表示されます。「チェーン」になっていると最初のメッセージでも失敗する別の (つまり、最初の受信者がメッセージを転送した場合、 など)。

これは、ユーザー アクティベーション v2 で、元の形式と チェーン化します。