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ć coś tak prostego jak wyświetlanie obrazów przesłanych przez użytkowników (np. zdjęć profilowych) lub tak złożonego jak renderowanie kodu HTML kontrolowanego przez użytkownika (np. samouczek programowania stron internetowych). Zawsze było to trudne do zrobienia w bezpieczny sposób, dlatego staraliśmy się znaleźć proste, ale bezpieczne rozwiązania, które można stosować w większości aplikacji internetowych.

Klasyczne rozwiązania do izolowania niesprawdzonych treści

Klasycznym rozwiązaniem zapewniającym bezpieczne wyświetlanie treści kontrolowanych przez użytkownika jest użycie tzw. domen piaskownicy. Zasada jest taka, że jeśli główna domena aplikacji to example.com, możesz wyświetlać wszystkie niesprawdzone treści na stronie exampleusercontent.com. Ponieważ te 2 domeny są dostępne w wielu witrynach, złośliwe treści w domenie exampleusercontent.com nie mogą mieć wpływu na domenę example.com.
Tego podejścia można używać do bezpiecznego wyświetlania wszelkich niesprawdzonych treści, w tym obrazów, plików do pobrania i HTML. Może się wydawać, że nie jest to konieczne w przypadku obrazów lub plików do pobrania, ale takie działanie pomaga 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 dobrze się sprawdzają. Mają jednak 2 główne wady:

  • Aplikacje często muszą ograniczać dostęp do treści do jednego użytkownika, co wymaga implementacji uwierzytelniania i autoryzacji. Domeny piaskownicy celowo nie udostępniają plików cookie głównej domenie aplikacji, więc jest to bardzo trudne do bezpiecznego wykonania. Aby obsługiwać uwierzytelnianie, witryny muszą polegać na adresach URL z możliwościami lub ustawiać osobne pliki cookie uwierzytelniania dla domeny piaskownicy. Ta druga metoda jest szczególnie problematyczna w przypadku współczesnego Internetu, w którym wiele przeglądarek domyślnie ogranicza pliki cookie na wielu stronach.
  • Treści użytkowników są odseparowane od głównej witryny, ale nie są odseparowane od treści innych użytkowników. Powoduje to ryzyko, że złośliwe treści użytkowników będą atakować inne dane w domenie piaskownicy (np. przez odczyt danych z tego samego pochodzenia).

Warto też pamiętać, że domeny piaskownicy pomagają ograniczać ryzyko wyłudzania informacji, ponieważ zasoby są wyraźnie podzielone na izolowaną domenę.

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

Z czasem internet się zmieniał, a obecnie istnieją łatwiejsze i bezpieczniejsze sposoby wyświetlania niesprawdzonych treści. Istnieje wiele różnych podejść, dlatego opiszemy 2 rozwiązania, które są obecnie szeroko stosowane w Google.

Podejście 1. Wyświetlanie treści nieaktywnych użytkowników

Jeśli witryna ma wyświetlać tylko nieaktywne treści użytkowników (czyli treści inne niż HTML lub JavaScript, np. obrazy i pliki do pobrania), może to bezpiecznie zrobić bez odizolowanej 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 nie zawiera aktywnych treści (w razie wątpliwości application/octet-stream to bezpieczny wybór).
  • Dodatkowo zawsze ustawiaj nagłówki odpowiedzi podane poniżej, aby zapewnić pełną izolację odpowiedzi.
Nagłówek odpowiedzi Purpose

X-Content-Type-Options: nosniff

zapobieganie podsłuchiwaniu treści,

Content-Disposition: attachment; filename="download"

powoduje pobranie zamiast renderowania;

Content-Security-Policy: sandbox

umieszcza treści w piaskownicy tak, jakby były one wyświetlane w osobnej domenie;

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

Wyłącza wykonywanie kodu JavaScript (oraz uwzględnianie dowolnych 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 aplikacja może wczytać odpowiedź tylko jako podreś, a użytkownik może ją pobrać jako plik. Ponadto nagłówki zapewniają wielowarstwową ochronę przed błędami w przeglądarce dzięki nagłówkowi sandboxu CSP i ograniczeniu default-src. Ogólnie konfiguracja opisana powyżej zapewnia wysoki poziom pewności, że odpowiedzi wyświetlane w ten sposób nie mogą prowadzić do podatności na wstrzyknięcie lub izolację.

Obrona w głąb

Powyższe rozwiązanie stanowi zwykle wystarczającą ochronę przed atakami XSS, ale możesz zastosować kilka dodatkowych środków wzmacniających, 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ć możliwość osadzenia punktu końcowego.
  • Treści użytkowników w sandboxie na odizolowanej subdomenie:
    • wyświetlanie treści użytkowników w odseparowanej domenie podrzędnej (np. Google używa do tego domen takich jak product.usercontent.google.com).
    • Ustaw Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp, aby włączyć izolację zasobów z różnych domen.

Metoda 2. Wyświetlanie treści użytkownikom aktywnym

Bezpieczne wyświetlanie aktywnych treści (np. obrazów HTML lub SVG) jest możliwe bez słabości klasycznego podejścia do piaskownicy.
Najprostszą opcją jest skorzystanie z nagłówka Content-Security-Policy: sandbox, aby poinformować przeglądarkę o wyodrębnieniu odpowiedzi. Chociaż nie wszystkie przeglądarki internetowe implementują obecnie izolację procesów w przypadku dokumentów w piaskownicy, stałe udoskonalanie modeli procesów przeglądarki prawdopodobnie poprawi oddzielenie treści w piaskownicy od aplikacji do umieszczania. Jeśli ataki SpectreJS i kompromitacji modułu renderującego wykraczają poza Twój model zagrożeń, prawdopodobnie wystarczy użycie piaskownicy CSP.
W Google opracowaliśmy rozwiązanie, które umożliwia pełną izolację niesprawdzonych aktywnych treści poprzez unowocześnienie koncepcji domen piaskownicy. Główna idea polega na:

  • Utwórz nową domenę piaskownicy, która zostanie dodana do listy publicznych sufiksów. Na przykład dodanie exampleusercontent.com do PSL pozwala zapewnić, aby foo.exampleusercontent.com i bar.exampleusercontent.com były dostępne w wielu witrynach i w ten sposób całkowicie od siebie odseparowane.
  • Adresy URL pasujące do *.exampleusercontent.com/shim są kierowane do statycznego pliku shim. Ten plik zawiera krótki fragment kodu HTML i JavaScriptu, który odbiera zdarzenia message i renderuje otrzymane treści.
  • W tym celu usługa tworzy iframe lub wyskakujące okienko dla $RANDOM_VALUE.exampleusercontent.com/shim i używa postMessage, aby wysłać niesprawdzone treści do shimu w celu renderowania.
  • Wyrenderowane treści są przekształcane w Bloba i renderowane w ramach elementu iframe w piaskownicy.

W porównaniu z klasycznym podejściem do piaskownicy domeny zapewnia to, że wszystkie treści są całkowicie odizolowane w unikalnej witrynie. Ponieważ główna aplikacja zajmuje się pobieraniem danych do renderowania, nie trzeba już używać adresów URL funkcji.

Podsumowanie

Te 2 rozwiązania umożliwiają migrację z klasycznych domen 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 korzystać z tych rozwiązań, a w przyszłym roku planujemy przeprowadzić kolejne.