Wiele aplikacji internetowych musi wyświetlać treści kontrolowane przez użytkowników. Może to być tak proste, jak wyświetlanie obrazów przesłanych przez użytkowników (np. zdjęć profilowych), lub tak złożone, jak renderowanie kodu HTML kontrolowanego przez użytkownika (np. w samouczku dotyczącym tworzenia 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 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żytkownika jest używanie tzw. domen piaskownicy. Podstawowa zasada jest taka, że jeśli główna domena aplikacji to example.com, możesz wyświetlać wszystkie niezaufane treści w domenie exampleusercontent.com. Ponieważ te 2 domeny są wieloma witrynami, żadne złośliwe treści w domenie exampleusercontent.com nie mogą mieć wpływu na domenę example.com.
Takie podejście pozwala bezpiecznie udostępniać wszystkie rodzaje niezaufanych treści, w tym obrazy, pliki do pobrania i HTML. Chociaż może się wydawać, że nie jest to konieczne w przypadku obrazów lub pobieranych plików, pomaga to uniknąć ryzyka związanego z wykrywaniem typu treści, zwłaszcza w starszych przeglądarkach.
Domena piaskownicy jest powszechnie stosowana w branży i od dawna dobrze się sprawdza. Mają jednak 2 główne wady:
- Aplikacje często muszą ograniczać dostęp do treści do jednego użytkownika, co wymaga wdrożenia uwierzytelniania i autoryzacji. Ponieważ domeny piaskownicy celowo nie udostępniają plików cookie domenie głównej aplikacji, bezpieczne wykonanie tej czynności jest bardzo trudne. Aby obsługiwać uwierzytelnianie, witryny muszą korzystać z adresów URL funkcji lub ustawiać osobne pliki cookie uwierzytelniania dla domeny piaskownicy. Ta druga metoda jest szczególnie problematyczna w nowoczesnej sieci, w której wiele przeglądarek domyślnie ogranicza pliki cookie innych witryn.
- Treści użytkowników są odseparowane od głównej witryny, ale nie od innych treści użytkowników. Stwarza to ryzyko, że złośliwe treści użytkownika zaatakują inne dane w domenie piaskownicy (np. odczytując dane tego samego pochodzenia).
Warto też zauważyć, że domeny w piaskownicy pomagają ograniczać ryzyko wyłudzania informacji, ponieważ zasoby są wyraźnie podzielone na odizolowane domeny.
Nowoczesne rozwiązania do wyświetlania treści użytkowników
Internet z czasem się rozwinął i obecnie istnieją łatwiejsze i bezpieczniejsze sposoby wyświetlania niezaufanych treści. Istnieje wiele różnych podejść, dlatego przedstawimy 2 rozwiązania, których używamy w Google.
Podejście 1. Udostępnianie treści użytkownika nieaktywnym użytkownikom
Jeśli witryna musi udostępniać tylko nieaktywne treści użytkownika (czyli zawartość, która nie jest kodem HTML ani JavaScript, np. obrazy i pliki do pobrania), można to teraz bezpiecznie zrobić bez izolowanej domeny piaskownicy. W tym celu wykonaj 2 główne kroki:
- Zawsze ustawiaj nagłówek
Content-Typena dobrze znany typ MIME, który jest obsługiwany przez wszystkie przeglądarki i nie zawiera aktywnej zawartości. W razie wątpliwości bezpiecznym wyborem jestapplication/octet-stream. - Dodatkowo zawsze ustawiaj nagłówki odpowiedzi, aby mieć pewność, że przeglądarka w pełni izoluje odpowiedź.
| Nagłówek odpowiedzi | Purpose |
|---|---|
X-Content-Type-Options: nosniff |
Zapobiega wykrywaniu treści |
Content-Disposition: attachment; filename="download" |
Wywołuje pobieranie zamiast renderowania |
Content-Security-Policy: sandbox |
Umieszcza treści w piaskownicy tak, jakby były wyświetlane w oddzielnej domenie. |
Content-Security-Policy: default-src ‘none' |
Wyłącza wykonywanie JavaScriptu (i uwzględnianie wszelkich zasobów podrzędnych). |
Cross-Origin-Resource-Policy: same-site |
uniemożliwia włączenie strony w innej witrynie; |
Ta kombinacja nagłówków zapewnia, że odpowiedź może być wczytywana jako zasób podrzędny tylko przez Twoją aplikację lub pobierana jako plik przez użytkownika. Ponadto nagłówki zapewniają wiele warstw ochrony przed błędami przeglądarki dzięki nagłówkowi piaskownicy CSP i ograniczeniu default-src. Ogólnie rzecz biorąc, opisana konfiguracja zapewnia wysoki stopień pewności, że odpowiedzi wyświetlane w ten sposób nie mogą prowadzić do luk wstrzykiwania ani luk w zabezpieczeniach izolacji.
Obrona w głąb
Proponowane rozwiązanie stanowi ogólnie wystarczającą ochronę przed atakami XSS, ale możesz zastosować szereg dodatkowych środków wzmacniających, aby zapewnić dodatkowe warstwy zabezpieczeń:
- Ustaw
X-Content-Security-Policy: sandboxnagłówek, aby zapewnić zgodność z IE11. - Ustaw nagłówek
Content-Security-Policy: frame-ancestors 'none', aby zablokować osadzanie punktu końcowego. - Treści użytkowników w piaskownicy w izolowanej subdomenie:
- Wyświetlanie treści użytkowników w izolowanej subdomenie (np. Google używa domen takich jak
product.usercontent.google.com). - Ustaw wartości
Cross-Origin-Opener-Policy: same-originiCross-Origin-Embedder-Policy: require-corp, aby włączyć izolację zasobów z różnych domen.
- Wyświetlanie treści użytkowników w izolowanej subdomenie (np. Google używa domen takich jak
Podejście 2. Wyświetlanie treści użytkownika aktywnym użytkownikom
Bezpieczne wyświetlanie aktywnych treści (np. obrazów HTML lub SVG) jest też możliwe bez wad klasycznego podejścia do domeny piaskownicy.
Najprostszym rozwiązaniem jest użycie nagłówka Content-Security-Policy: sandbox, aby poinformować przeglądarkę o konieczności odizolowania odpowiedzi. Nie wszystkie przeglądarki internetowe implementują izolację procesów w przypadku dokumentów w piaskownicy, ale ciągłe udoskonalanie modeli procesów przeglądarki prawdopodobnie poprawi separację treści w piaskownicy od aplikacji osadzających. Jeśli ataki SpectreJS i renderer compromise nie mieszczą się w Twoim modelu zagrożeń, użycie piaskownicy CSP prawdopodobnie będzie wystarczającym rozwiązaniem.
W Google opracowaliśmy rozwiązanie, które umożliwia pełne odizolowanie niezaufanych aktywnych treści dzięki unowocześnieniu koncepcji domen piaskownicy. Główna idea polega na:
- Utwórz nową domenę piaskownicy, która zostanie dodana do listy sufiksów publicznych. Na przykład dodając
exampleusercontent.comdo listy PSL, możesz mieć pewność, żefoo.exampleusercontent.comibar.exampleusercontent.comsą domenami różnych witryn, a tym samym są od siebie całkowicie odizolowane. - Adresy URL pasujące do wzorca
*.exampleusercontent.com/shimsą kierowane do statycznego pliku shim. Ten plik shim zawiera krótki fragment kodu HTML i JavaScript, który nasłuchuje procedury obsługi zdarzeńmessagei renderuje wszystkie otrzymane treści. - Aby to zrobić, usługa tworzy element iframe lub okno dialogowe, aby
$RANDOM_VALUE.exampleusercontent.com/shim, i używapostMessagedo wysyłania niezaufanych treści do warstwy pośredniej w celu renderowania. - Wyrenderowana treść jest przekształcana w obiekt Blob i wyświetlana w elemencie iframe umieszczonym w piaskownicy.
W porównaniu z klasycznym podejściem do domeny piaskownicy zapewnia to pełną izolację wszystkich treści w unikalnej witrynie. Gdy 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ą przejście z klasycznych domen piaskownicy, takich jak googleusercontent.com, na bezpieczniejsze rozwiązania, które są zgodne z blokowaniem plików cookie innych firm. W Google wiele usług zostało już przeniesionych na te rozwiązania, a w przyszłym roku planujemy kolejne migracje.