Bezpieczne przechowywanie danych użytkowników w nowoczesnych aplikacjach internetowych

David Dworken
David Dworken

Wiele aplikacji internetowych musi wyświetlać treści kontrolowane przez użytkownika. Może to być tak proste, jak wyświetlanie obrazów przesłanych przez użytkowników (na przykład zdjęcia profilowe) lub bardzo złożone, jak renderowanie kontrolowanego przez użytkownika kodu HTML (na przykład samouczki dla programistów stron internetowych). Zawsze trudno było robić to w bezpieczny sposób, dlatego popracowaliśmy nad znalezieniem prostych, ale bezpiecznych rozwiązań, które można zastosować w większości typów aplikacji internetowych.

Klasyczne rozwiązania do izolowania niezaufanych treści

Klasycznym rozwiązaniem do bezpiecznego wyświetlania treści kontrolowanych przez użytkowników jest użycie domen piaskownicy. Ogólnie rzecz biorąc, jeśli główna domena aplikacji to example.com, w exampleusercontent.com mogą być wyświetlane wszystkie niezaufane treści. Ponieważ te 2 domeny występują w innych witrynach, jakiekolwiek złośliwe treści w exampleusercontent.com nie mogą mieć wpływu na example.com.
Korzystając z tej metody, można bezpiecznie wyświetlać wszelkiego rodzaju niezaufane treści, w tym obrazy, pliki do pobrania i kod HTML. Chociaż może się wydawać, że nie jest to konieczne w przypadku obrazów i pobieranych plików, pomaga to uniknąć ryzyka związanego z przechwytywaniem treści, zwłaszcza w starszych przeglądarkach.
Domeny piaskownicy są powszechnie używane w branży i od dawna sprawdzają się świetnie. Mają jednak 2 główne wady:

  • Często muszą ograniczać dostęp do treści do pojedynczego użytkownika, co wymaga wdrożenia uwierzytelniania i autoryzacji. Ponieważ domeny piaskownicy celowo nie udostępniają plików cookie głównej domenie aplikacji, jest to bardzo trudne do zrobienia. Aby obsługiwać uwierzytelnianie, witryny muszą polegać na adresach URL obsługi albo muszą ustawić osobne pliki cookie uwierzytelniania dla domeny piaskownicy. Ta druga metoda jest szczególnie problematyczna we współczesnych witrynach, w których wiele przeglądarek domyślnie ogranicza pliki cookie pochodzące z innych witryn.
  • Treści użytkowników są odizolowane od głównej witryny, ale nie od innych treści. Zwiększa to ryzyko, że złośliwe treści użytkowników zaatakują inne dane w domenie piaskownicy (na przykład przez odczyt danych z tej samej domeny).

Warto też pamiętać, że domeny w piaskownicy pomagają zmniejszyć ryzyko wyłudzania informacji, ponieważ zasoby są wyraźnie przyporządkowane do izolowanej domeny.

Nowoczesne rozwiązania do wyświetlania treści użytkowników

Z czasem sieć ewoluowała i teraz dostępne są łatwiejsze i bezpieczniejsze sposoby udostępniania niezaufanych treści. Istnieje wiele różnych rozwiązań, więc przedstawimy 2 rozwiązania, które są obecnie powszechnie używane w Google.

Sposób 1. Udostępnianie nieaktywnych treści użytkowników

Jeśli witryna ma wyświetlać tylko nieaktywne treści użytkownika (tzn. treści inne niż HTML czy JavaScript, np. obrazy i pobrane pliki), można to bezpiecznie zrobić bez wyodrębniania domeny piaskownicy. Musisz wykonać 2 kluczowe kroki:

  • Zawsze ustawiaj nagłówek Content-Type na dobrze znany typ MIME, który jest obsługiwany przez wszystkie przeglądarki i gwarantuje, że nie zawiera aktywnej treści (w razie wątpliwości zalecamy użycie application/octet-stream).
  • Oprócz tego zawsze ustawiaj poniższe nagłówki odpowiedzi, aby przeglądarka w pełni wyizolowała odpowiedź.
Nagłówek odpowiedzi Purpose

X-Content-Type-Options: nosniff

Zapobieganie podsłuchiwaniu treści

Content-Disposition: attachment; filename="download"

Powoduje pobieranie zamiast renderowania

Content-Security-Policy: sandbox

Umieszczanie treści w piaskownicy w taki sposób, jakby były one wyświetlane w osobnej domenie

Content-Security-Policy: default-src ‘none'

Wyłącza wykonywanie JavaScriptu (oraz uwzględnianie wszystkich zasobów podrzędnych)

Cross-Origin-Resource-Policy: same-site

Uniemożliwia uwzględnianie strony w innych witrynach

Ta kombinacja nagłówków zapewnia, że odpowiedź może zostać wczytana przez aplikację tylko jako zasób podrzędny lub jako plik przez użytkownika. Ponadto nagłówki zapewniają wielowarstwową ochronę przed błędami przeglądarki przez nagłówek piaskownicy CSP i ograniczenie default-src. Ogólnie opisana konfiguracja daje wysoki stopień pewności, że odpowiedzi wysyłane w ten sposób nie mogą prowadzić do wstrzykiwania ani izolowania luk w zabezpieczeniach.

Obrona w głąb

Powyższe rozwiązanie stanowi zwykle wystarczającą ochronę przed atakami XSS, ale istnieje wiele dodatkowych środków wzmacniających, które można zastosować, aby zapewnić dodatkowe warstwy zabezpieczeń:

  • Ustaw nagłówek X-Content-Security-Policy: sandbox, aby zapewnić zgodność z IE11.
  • Ustaw nagłówek Content-Security-Policy: frame-ancestors 'none', aby zablokować umieszczanie punktu końcowego.
  • Treści użytkowników w piaskownicy w izolowanej subdomenie według:
    • wyświetlanie treści użytkowników w izolowanej subdomenie (np. Google korzysta z domen takich jak product.usercontent.google.com);
    • Ustaw Cross-Origin-Opener-Policy: same-origin i Cross-Origin-Embedder-Policy: require-corp, aby włączyć izolację zasobów z innych domen.

Sposób 2: udostępnianie treści aktywnych użytkowników

Bezpieczne wyświetlanie aktywnych treści (np. obrazów HTML czy SVG) można też zrealizować bez słabości klasycznego podejścia do domeny piaskownicy.
Najprostszym sposobem jest wykorzystanie nagłówka Content-Security-Policy: sandbox do poinformowania przeglądarki o wyizolowaniu odpowiedzi. Chociaż nie wszystkie przeglądarki internetowe implementują izolację procesów dla dokumentów w trybie piaskownicy, ciągłe udoskonalanie modeli procesów przeglądarki prawdopodobnie poprawi oddzielenie treści w trybie piaskownicy od aplikacji umieszczonych na stronach. Jeśli ataki SpectreJS i złamanie zabezpieczeń mechanizmu renderowania znajdują się poza modelem zagrożeń, odpowiednim rozwiązaniem może okazać się piaskownica CSP.
W Google opracowaliśmy rozwiązanie, które może całkowicie wyizolować niezaufane aktywne treści, zmieniając koncepcję domen piaskownicy. Głównym celem jest:

  • Utwórz nową domenę piaskownicy, która zostanie dodana do listy domen publicznych. Na przykład dodając exampleusercontent.com do PSL, możesz zapewnić, że foo.exampleusercontent.com i bar.exampleusercontent.com są umieszczone w różnych witrynach, a tym samym w pełni odizolowane.
  • Wszystkie adresy URL pasujące do atrybutu *.exampleusercontent.com/shim są kierowane do statycznego pliku podkładki. Ten plik podkładki zawiera krótki fragment kodu HTML i JavaScript, który nasłuchuje modułu obsługi zdarzenia message i renderuje otrzymaną treść.
  • W tym celu usługa tworzy element iframe lub wyskakujące okienko z adresem $RANDOM_VALUE.exampleusercontent.com/shim i używa postMessage do wysyłania niezaufanych treści do podkładki w celu wyrenderowania.
  • Wyrenderowana treść jest przekształcana w obiekt blob i renderowana w elemencie iframe w trybie piaskownicy.

W porównaniu z klasycznym podejściem do domeny piaskownicy gwarantuje to, że wszystkie treści w jednej witrynie są w pełni odizolowane. Ponieważ główna aplikacja zajmuje się pobieraniem danych do renderowania, nie trzeba już korzystać z adresów URL dostępnych funkcji.

Podsumowanie

Połączenie tych 2 rozwiązań umożliwia migrację z klasycznych domen w trybie piaskownicy, takich jak googleusercontent.com, do bezpieczniejszych rozwiązań, które są zgodne z blokowaniem plików cookie innych firm. W Google przeprowadziliśmy już migrację wielu usług, aby zacząć korzystać z tych rozwiązań, a na przyszły rok planujemy kolejne migracje.