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ściapplication/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-origin
iCross-Origin-Embedder-Policy: require-corp
, aby włączyć izolację zasobów z różnych domen.
- wyświetlanie treści użytkowników w odseparowanej domenie podrzędnej (np. Google używa do tego domen takich jak
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ć, abyfoo.exampleusercontent.com
ibar.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 zdarzeniamessage
i renderuje otrzymane treści. - W tym celu usługa tworzy iframe lub wyskakujące okienko dla
$RANDOM_VALUE.exampleusercontent.com/shim
i używapostMessage
, 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.