Rendre l'activation des utilisateurs cohérente entre les API

Mustaq Ahmed
Joe Medley
Joe Medley

Pour empêcher les scripts malveillants d'utiliser abusivement les API sensibles telles que les pop-ups, plein écran, etc., les navigateurs contrôlent l'accès à ces API via des identifiants l'activation. L'activation utilisateur correspond à l'état d'une session de navigation par rapport à aux actions de l'utilisateur : implique généralement que l'utilisateur interagit actuellement avec la page ou a effectué une interaction depuis la page de votre application. Le geste de l'utilisateur est un terme populaire, mais trompeur qui désigne la même idée. Pour Par exemple, un geste de balayage ou d'effleurement d'un utilisateur n'active pas la page et, par conséquent, n'est pas une activation utilisateur du point de vue du script.

Aujourd'hui, les principaux navigateurs présentent des comportements très différents concernant l'activation des utilisateurs contrôle les API dont l'activation est contrôlée. Dans Chrome, l'implémentation se basait sur un modèle basé sur des jetons qui s'est avéré trop complexe pour définir de toutes les API dont l'activation est contrôlée. Par exemple, Chrome a été permettant un accès incomplet aux API soumises à un contrôle d'activation postMessage() et setTimeout() appels ; et l'activation utilisateur n'était pas compatible avec les promesses, XHR, Interaction avec la manette de jeu, etc. Notez que certains de ces sont des insectes populaires, mais depuis longtemps.

Dans la version 72, Chrome propose l'activation utilisateur v2, qui permet aux utilisateurs Disponibilité de l'activation terminée pour toutes les API dont l'activation est contrôlée Cette opération résout les incohérences mentionnées ci-dessus (et quelques autres, comme MessageChannels), qui, selon nous, permettrait de simplifier le Web développement autour de l'activation des utilisateurs. De plus, la nouvelle implémentation offre une implémentation de référence pour une proposition nouvelle spécification qui vise à réunir tous les navigateurs sur le long terme.

Comment fonctionne User Activation v2 ?

La nouvelle API maintient un état d'activation utilisateur de deux bits à chaque objet window dans la hiérarchie des frames: un bit persistant pour l'historique d'activation de l'utilisateur (si un l'image n'a jamais été activée par un utilisateur), et un bit temporaire pour l'état actuel (si une image a été activée par l'utilisateur au bout d'une seconde environ). La bande adhésive ne se réinitialise jamais pendant la durée de vie de l'image après sa configuration. Le bit transitoire est défini à chaque interaction de l'utilisateur et est réinitialisé (environ une seconde) ou via un appel à une API consommant des données d'activation (par exemple, window.open()).

Notez que les différentes API dont l'activation est contrôlée dépendent de l'activation de l'utilisateur dans différentes manières ; la nouvelle API ne modifie aucun de ces comportements spécifiques. Exemple : une seule fenêtre pop-up est autorisée par activation utilisateur, car window.open() utilise l'activation utilisateur, Navigator.prototype.vibrate() continue de être efficaces si un frame (ou l'un de ses sous-cadres) a déjà fait l'objet d'une action de l'utilisateur ; et ainsi de suite.

Ce qui change

  • User Activation v2 formalise la notion de visibilité sur l'activation des utilisateurs au-delà des limites d'un frame: toute interaction d'un utilisateur avec une image particulière activer tous les cadres conteneurs (et uniquement ceux-ci), indépendamment de leur origine. (Dans Chrome 72, une solution temporaire est en place pour développer le la visibilité de tous les frames de même origine. Nous supprimerons cette solution de contournement trouver un moyen de transmettre explicitement l'activation de l'utilisateur aux sous-cadres.)
  • Lorsqu'une API contrôlée par l'activation est appelée depuis un frame activé, mais depuis en dehors du code d'un gestionnaire d'événements, elle fonctionnera tant que l'activation de l'utilisateur l'état est "actif" (par exemple, n'a pas expiré ni n'a été consommée). Avant l'utilisateur L'activation v2 échouerait sans condition.
  • Plusieurs interactions utilisateur inutilisées dans l'intervalle d'expiration sont fusionnées en une seule activation correspondant à la dernière interaction.

Exemples de cohérence dans les API avec contrôle d'activation

Voici deux exemples de fenêtres pop-up (ouvertes avec window.open()) qui : illustrer comment User Activation v2 gère le comportement des API dont l'activation est contrôlée cohérentes.

Appels setTimeout() enchaînés

Cet exemple provient de notre démonstration setTimeout(). Si un gestionnaire click tente d'ouvrir un pop-up en l'espace d'une seconde, il devrait quelle que soit la façon dont le code "se compose" le délai. Activation utilisateur v2 : cette attente. Chacun des gestionnaires d'événements suivants ouvre donc un pop-up sur une click (avec un délai de 100 ms):

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

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

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

Sans User Activation v2, le deuxième gestionnaire d'événements échoue dans tous les navigateurs sont testées. (Même le premier échoue dans certains cas).

Appels postMessage() interdomaines

Voici un exemple tiré de notre démonstration postMessage(). Supposons qu'un gestionnaire click dans un sous-frame d'origines multiples envoie directement deux messages au cadre parent. Le cadre parent doit pouvoir ouvrir un pop-up lorsque recevoir l'un des messages suivants (mais pas les deux):

// 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);
});

Sans User Activation v2, le cadre parent ne peut pas ouvrir un pop-up à la réception le deuxième message. Même le premier message échoue s'il est "enchaîné" vers une autre trame multi-origine (en d'autres termes, si le premier destinataire transfère le message vers un autre).

Cela fonctionne avec User Activation v2, à la fois dans sa forme initiale et avec l' et le chaînage.