Einheitliche Nutzeraktivierung über APIs hinweg

Mustaq Ahmed
Joe Medley
Joe Medley

Um zu verhindern, dass schädliche Skripts vertrauliche APIs wie Pop-ups missbrauchen, Vollbild usw. steuern Browser den Zugriff auf diese APIs über Nutzer, Aktivierung. Die Nutzeraktivierung ist der Status einer Browsersitzung in Bezug auf zu Nutzeraktionen: „aktiv“, bedeutet in der Regel, dass die Nutzenden die derzeit mit der Seite interagieren oder seit der Seite eine Interaktion abgeschlossen hat. laden. Nutzergeste ist ein beliebter, aber irreführender Begriff für dieselbe Idee. Für Beispiel: Durch eine Wisch- oder Wischgeste eines Nutzers wird eine Seite nicht aktiviert. aus Skriptsicht keine Aktivierung durch den Nutzer ist.

Bei den meisten gängigen Browsern ist das Verhalten bei der Nutzeraktivierung sehr unterschiedlich. steuert die Aktivierungs-Gated APIs. In Chrome basierte die Implementierung auf auf einem tokenbasierten Modell, das sich als zu komplex erwiesen hat, um ein einheitliches für alle aktivierungsgesteuerten APIs. Chrome wurde zum Beispiel der unvollständigen Zugriff auf aktivierungsgesteuerte APIs über postMessage() und setTimeout() Aufrufe; und die Nutzeraktivierung war unterstützt Promise-Objekte, XHR Gamepad-Interaktion usw. Beachten Sie, dass einige dieser sind beliebte, aber seit Langem bestehende Insekten.

In Version 72 bietet Chrome die Nutzeraktivierung v2 an, Verfügbarkeit der Aktivierung für alle aktivierungsgesteuerten APIs abgeschlossen. Dadurch wird die oben erwähnten Unstimmigkeiten (und ein paar weitere, MessageChannels, das unserer Meinung nach zur Nutzeraktivierung entwickelt. Darüber hinaus bietet die neue Implementierung eine Referenzimplementierung für eine vorgeschlagene neue Spezifikation das langfristig alle Browser zusammenbringen soll.

Wie funktioniert die Nutzeraktivierung v2?

Die neue API behält bei jedem window-Objekt einen 2-Bit-Nutzeraktivierungsstatus bei. in der Frame-Hierarchie: ein Sticky Bit für den Verlauf der Nutzeraktivierung (wenn ein Frame eine Nutzeraktivierung gesehen hat) und ein vorübergehendes Bit für den aktuellen Zustand. (wenn ein Frame innerhalb von etwa einer Sekunde eine Nutzeraktivierung erkannt hat). Der Sticky Bit wird während seiner Lebensdauer nie zurückgesetzt. Das vorübergehende Bit wird für jede Nutzerinteraktion festgelegt und entweder nach Ablauf des (etwa eine Sekunde) oder durch einen Aufruf an eine API, die die Aktivierung nutzt, (z.B. window.open()).

Beachten Sie, dass verschiedene aktivierungsgesteuerte APIs von der Nutzeraktivierung in unterschiedlichen Methoden: Durch die neue API ändert sich an diesen API-spezifischen Verhaltensweisen nichts. Beispiel: Pro Nutzeraktivierung ist nur ein Pop-up zulässig, da window.open() verbraucht wie zuvor aktiviert, setzt Navigator.prototype.vibrate() ist effektiv, wenn ein Frame (oder einer seiner Subframes) jemals eine Nutzeraktion, und so weiter.

Was ändert sich?

  • Durch die Nutzeraktivierung (v2) wird das Konzept der Sichtbarkeit der Nutzeraktivierung formalisiert. über Frame-Grenzen hinweg: Bei einer Nutzerinteraktion mit einem bestimmten Frame aktivieren Sie alle beinhaltenden Frames (und nur diese Frames), unabhängig von ihren Ursprung. In Chrome 72 haben wir eine vorübergehende Problemumgehung implementiert, um die für alle Frames mit demselben Ursprung. Wir werden diese Behelfslösung entfernen, sobald wir Möglichkeit haben, die Nutzeraktivierung explizit an Subframes übergeben.)
  • Wenn eine aktivierungsgesteuerte API von einem aktivierten Frame aus Ereignis-Handler-Code befindet, funktioniert er, solange die Nutzeraktivierung Status ist „aktiv“ (d. h., weder abgelaufen noch verbraucht) Vor Nutzer Bei Aktivierung von Version 2 würde sie ohne Einschränkungen fehlschlagen.
  • Mehrere nicht verwendete Nutzerinteraktionen innerhalb des Ablaufzeitraums werden zusammengeführt in eine einzelne Aktivierung umwandeln, die der letzten Interaktion entspricht.

Beispiele für Konsistenz in aktivierungsgesteuerten APIs

Hier zwei Beispiele mit Pop-up-Fenstern (mit window.open() geöffnet), die Zeigen, wie die Benutzeraktivierung v2 das Verhalten von aktivierungsgesteuerten APIs verändert einheitlich sind.

Verkettete setTimeout()-Anrufe

Dieses Beispiel stammt aus unsere setTimeout()-Demo. Wenn ein click-Handler versucht, innerhalb einer Sekunde ein Pop-up zu öffnen, wird erwartet, unabhängig davon, wie sich der Code die Verzögerung. Nutzeraktivierung v2 erfüllt Erwartung erfüllt. Daher öffnet jeder der folgenden Event-Handler ein Pop-up auf einem click (mit 100 ms Verzögerung):

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

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

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

Ohne die Nutzeraktivierung v2 schlägt der zweite Event-Handler in allen Browsern fehl, getestet. (Auch die erste scheitert in einigen Fällen).

Domainübergreifende postMessage()-Aufrufe

Hier ist ein Beispiel aus unsere postMessage()-Demo. Angenommen, ein click-Handler in einem ursprungsübergreifenden Subframe sendet zwei Nachrichten direkt zum übergeordneten Frame hinzu. Der übergeordnete Frame sollte in der Lage sein, ein Pop-up-Fenster zu öffnen, eine der folgenden Nachrichten erhalten (aber nicht beide):

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

Ohne Nutzeraktivierung v2 kann über den übergeordneten Frame beim Empfang kein Pop-up-Fenster geöffnet werden. in der zweiten Nachricht. Selbst die erste Nachricht schlägt fehl, wenn sie verkettet wird. zu einem anderen ursprungsübergreifenden Frame (d. h., wenn der erste Empfänger die Nachricht in ein anderes).

Dies funktioniert mit der Nutzeraktivierung v2, sowohl im ursprünglichen Formular als auch mit der Verkettungen.