Przewiń do treści 

Pozwolenie A38

Opublikowany:
Autor:
Comandeer
Kategorie:
Adwent 2025
Standardy sieciowe

Wszyscy to znamy. Chcemy coś zrobić w przeglądarce i pojawia się to wkurzające okienko z prośbą o pozwolenie:

Wyskakujące okienko w przeglądarce Chrome z zapytaniem, czy pozwolić stronie http://localhost:3000 na odczytywanie tekstu i obrazków ze schowka systemowego, oraz przyciskami "Block" i "Allow".
Kliknij obrazek, aby go powiększyć

Ale czasami może być gorzej. Czasami trzeba mieć pozwolenie na pozwolenie

Potężne ficzery

Dawno, dawno temu pojawiła się specyfikacja pod intrygującą nazwą Requirements for Powerful Features (Wymagania dla Potężnych Ficzerów). Niestety, nazwa została zmieniona i obecnie mamy Secure Contexts (Bezpieczne Konteksty). A szkoda, bo nowej nazwie brakuje tego czegoś. Dodatkowo uważam, że stara o wiele lepiej oddawała, o co chodzi w tym dokumencie.

A chodzi o to, że w przeglądarkach są obecnie ficzery, którymi można zrobić krzywdę, jeśli użyje się ich niezgodnie z przeznaczeniem. Dobrym przykładem jest tutaj Clipboard API, które pozwala odczytywać tekst z systemowego schowka. Dlatego też przeglądarki stosują dodatkowe środki ochronne, by nie dało się użyć tego API w niecnych celach. Podstawową formą ochrony jest wymuszanie bezpiecznego połączenia przez HTTPS (stąd zresztą nazwa bezpieczne konteksty). Niemniej nie jest to jedyny sposób ochrony. Kolejnym jest tzw. user activation (aktywacja przez osobę użytkowniczą).

Aktywacja przez osobę użytkowniczą

Wyobraźmy sobie następującą sytuację: szukamy jakiejś informacji w Google. Klikamy na jeden z wyników i trafiamy na jakąś dziwną, podejrzaną stronę. Natychmiast ją zamykamy… Ale jest już za późno, bo zdążyła odczytać zawartość naszego schowka i zdobyć tym samym numer naszej karty kredytowej. Na całe szczęście to całkowicie nierealny scenariusz – i nie tylko dlatego, że raczej nikt nie ma ot tak skopiowanego numeru swojej karty. Żeby strona mogła odczytać dane ze schowka, muszą być spełnione dwa warunki:

  1. musimy udzielić stronie pozwolenia na odczytywanie danych ze schowka,
  2. strona musi być aktywowana.

To oznacza, że nawet zaufana strona, której udzielimy pozwolenia na dostęp do schowka, nie będzie mogła sobie ot tak odczytać z niego danych. Weźmy taki kod:

setTimeout( async () => { // 1
	const text = await navigator.clipboard.readText(); // 3

	alert( text ); // 4
}, 2000 ); // 2

Ustawiamy timer (1) na 2 sekundy (2). Gdy miną, odczytujemy tekst ze schowka (3) i wyświetlamy go w wyskakującym alercie (4).

Jeśli wejdziemy teraz na taką stronę i nie będziemy w nią klikać ani w żaden inny sposób wchodzić z nią w interakcję, wyskakujące okienko się nie pokaże. Natomiast w konsoli pojawi się błąd:

Uncaught (in promise) NotAllowedError: Failed to execute 'readText' on 'Clipboard': Document is not focused.

Powyższy błąd pochodzi z Chrome’a. W Firefoksie wygląda nieco inaczej:

Uncaught (in promise) DOMException: Clipboard read request was blocked due to lack of user activation.

Innymi słowy: schowek potrzebuje aktywacji ze strony osoby użytkowniczej. Co to jednak oznacza? W największym skrócie: dopóki osoba użytkownicza nie kliknie w stronę, nie naciśnie żadnego klawisza na klawiaturze, nie sfocusuje strony, to ta pozostanie nieaktywowana. Dopiero, gdy osoba użytkownicza wykaże jakiekolwiek zainteresowanie stroną, wówczas przeglądarka pozwoli odczytać tekst ze schowka.

Co to jednak znaczy wykazać zainteresowanie? Standard jest mocno precyzyjny w tym zakresie. Aktywacja zachodzi wtedy, gdy akcja osoby użytkowniczej odpali jedno ze zdarzeń:

Te zdarzenia muszą być zaufane, więc nie da się ich stworzyć w kodzie, muszą być rezultatem akcji ze strony osoby użytkowniczej.

Dodatkowo wyróżnić można dwa typy aktywacji:

  • przyczepiona (sticky) – akcja ze strony osoby użytkowniczej zaszła w dowolnym momencie od wczytania strony, np. ktoś kliknął przycisk 5 minut temu i od tego czasu nic więcej nie robił,
  • przelotna (transient) – akcja ze strony osoby użytkowniczej właśnie się dzieje (np. ktoś klika przycisk) lub wydarzyła się góra kilka sekund temu.

W zależności od API, może ono wymagać jednego albo drugiego typu aktywacji. Dostęp do schowka wymaga tej przelotnej – żeby zagwarantować, że osoba użytkownicza faktycznie chce dać stronie ten dostęp. Na MDN-ie jest lista API wymagających aktywacji.

Warto też wspomnieć o własności navigator.userActivation, która zwraca informacje o stanie aktywacji strony:

console.log( navigator.userActivation ); // { hasBeenActive: true, isActive: true }

Zwracany obiekt ma dwie własności:

  • hasBeenActive – pokazującą, czy zaszła przyczepiona aktywacja,
  • isActive – pokazującą, czy zachodzi przelotna aktywacja.

Dzięki temu prostemu API można się łatwo dowiedzieć, czy mamy już nasze pozwolenie na pozwolenie.

Komentarze

Przejdź do komentarzy bezpośrednio na Githubie.