Każdy skrypt firm trzecich na stronie płatności, logowania czy w panelu administracyjnym działa z takimi samymi uprawnieniami jak użytkownik, który go załadował. Jeśli serwer hostujący ten skrypt zostanie przejęty, atakujący dostaje te same uprawnienia, podobnie jak w przypadku XSS. Rozwiązanie zaczyna się od ustalenia, jakie skrypty się ładują, a następnie usunięcia tego, co się da, i przypięcia lub ograniczenia reszty.
Wiedz, co działa na wrażliwych stronach
Ściągawka OWASP o zarządzaniu zewnętrznym JavaScriptem wymienia trzy ryzyka: utratę kontroli nad zmianami w aplikacji klienckiej, wykonywanie dowolnego kodu na systemach klientów oraz wyciek wrażliwych informacji do stron trzecich. Wśród przykładów są incydent Ticketmaster z 2018 roku i śledztwo ClearSky dotyczące kradzieży danych płatniczych przez Magecart.
Inwentaryzację przeprowadź strona po stronie, zaczynając od checkoutu, logowania i panelu administracyjnego. Dla każdego skryptu zapisz adres URL, właściciela biznesowego, powód, dla którego się tam znalazł, oraz sposób, w jaki trafia na stronę. OWASP opisuje trzy ścieżki dostarczenia: kod dostawcy wklejony w stronę, tag <script src> wskazujący na dostawcę oraz pośrednie żądanie przez tag manager.
Najmniej widoczny jest tag manager. Może zwracać skrypty od wielu dostawców, a pracownicy mogą zmieniać to, co zwraca, przez interfejs webowy, bez dotykania Twojego kodu. Zmiany trafiają na produkcję przy następnym załadowaniu strony, a sam kod jest zwykle zaciemniony.
Źródło HTML nie pokaże tych skryptów. Otwórz narzędzia deweloperskie, przejdź na kartę Network, przejdź cały proces zakupowy i logowania, a następnie wypisz każdy host, z którego pochodzi jakiś skrypt.
Najpierw usuń, potem zrób kopię lokalną
Zapytaj właściciela każdej pozycji, czy w ogóle musi ona być na tej stronie. Tag marketingowy na stronie logowania lub w panelu administracyjnym rzadko ma dobre uzasadnienie.
Dla skryptów, które zostają, OWASP wymienia jako zabezpieczenie hostowanie kopii we własnej infrastrukturze. Przeglądaną kopię trzymasz u siebie, więc strona trzecia nie może jej zmienić, a dostawca przestaje otrzymywać adres IP odwiedzającego, referrer i ciasteczka. Koszt to utrzymanie: kopia lokalna nie dostaje poprawek dostawcy, więc ktoś musi odpowiadać za jej ponowny przegląd i odświeżanie.
Osobnym problemem są porzuceni dostawcy. Jeśli domena hostująca skrypt wygaśnie, bo dostawca zbankrutował lub porzucił projekt, ktoś może ją zarejestrować ponownie i opublikować złośliwy kod. Martwy dostawca na Twojej liście to sam w sobie znalezisko.
Przypnij to, co zostaje, za pomocą Subresource Integrity
Subresource Integrity (SRI) pozwala stronie określić hash, któremu musi odpowiadać plik. Przed wykonaniem skryptu lub zastosowaniem arkusza stylów przeglądarka porównuje pobrany plik z tym hashem i zwraca błąd sieciowy, jeśli się różnią. Przewodnik MDN o SRI podaje polecenie generujące hash:
cat FILENAME.js | openssl dgst -sha384 -binary | openssl base64 -A
Dodaj przed wynikiem prefiks sha384- i umieść go w elemencie:
<script src="https://cdn.example.com/script.js"
integrity="sha384-..."
crossorigin="anonymous"></script>
Znacznik musi spełniać kilka wymagań:
- Atrybut
crossoriginjest wymagany. Przeglądarka odrzuca SRI dla żądańno-cors, więc tag bez niego zawsze zakończy się błędem. - CDN musi wysyłać nagłówek
Access-Control-Allow-Origin. Wiele z nich wysyła*. - Możesz podać kilka hashy. Przeglądarka używa tylko tych z najsilniejszego obecnego algorytmu (SHA-256, SHA-384, SHA-512 w kolejności rosnącej) i akceptuje plik, jeśli pasuje którykolwiek z nich, co pozwala dopuścić dwie wersje podczas aktualizacji. Specyfikacja W3C opisuje to samo zachowanie.
SRI pasuje do plików, które nie zmieniają się, dopóki sam ich nie zmienisz. Skrypt, który dostawca edytuje według uznania, nie przejdzie weryfikacji po każdej edycji, a kontener tag managera jest właśnie takim skryptem. Ogranicz krąg osób, które mogą w nim publikować, i nie umieszczaj go na swoich najbardziej wrażliwych stronach.
Ogranicz za pomocą Content Security Policy
SRI mówi, co dany plik musi zawierać. Content Security Policy (CSP) określa, skąd w ogóle mogą pochodzić skrypty. Przewodnik MDN o CSP zaleca dostarczanie jej w nagłówku Content-Security-Policy we wszystkich odpowiedziach, nie tylko w głównym dokumencie.
Punkt wyjścia dla wrażliwej strony wymienia hosty, z których faktycznie korzystasz:
Content-Security-Policy: script-src 'self' cdn.example.com; object-src 'none'
Gdy pojawi się dyrektywa script-src lub default-src, inline JavaScript jest blokowany, o ile go nie włączysz. MDN radzi unikać 'unsafe-inline', ponieważ niweczy znaczną część sensu CSP. Tam, gdzie potrzebujesz skryptów inline, użyj nonce: generowanego dla każdej odpowiedzi, nieprzewidywalnego i wstawianego przez szablon. Dla stron statycznych MDN proponuje zamiast tego hashe, a skrypty zewnętrzne wymagają wtedy również atrybutu integrity.
OWASP stwierdza wprost, że data layer nie jest piaskownicą, ponieważ kontenery tag managerów mogą wykonywać własny JavaScript i HTML. Ogranicz dostęp do publikowania i przeglądaj zmiany tak jak kod aplikacji.
Znajdź luki, nie psując witryny
Nagłówek Integrity-Policy sprawia, że przeglądarka blokuje skrypty bez atrybutu integrity lub ładowane w trybie no-cors. Zacznij od wersji report-only:
Integrity-Policy-Report-Only: blocked-destinations=(script), endpoints=(integrity-endpoint)
Endpoint wymaga odpowiadającego mu nagłówka Reporting-Endpoints. Naruszenia docierają jako raporty typu integrity-violation, wskazujące zablokowany adres URL. Przypięte skrypty znikają z raportów, więc nie stanowią one pełnej inwentaryzacji skryptów.
Gdy raporty przestaną napływać, według MDN włączenie blokowania jest bezpieczne i nie powoduje problemów po stronie użytkowników. Kontener tag managera, którego nie możesz przypiąć, stale generuje raporty, więc strony, które go ładują, pozostają w trybie report-only. Nagłówki wysyłane przez Twoje strony możesz sprawdzić za pomocą naszego sprawdzacza nagłówków HTTP.
Od czego zacząć
- Zbuduj inwentarz dla stron checkoutu, logowania i panelu administracyjnego na podstawie karty Network, zapisując dla każdego skryptu właściciela, cel i sposób dostarczenia.
- Usuń pozycje, których nikt nie potrafi uzasadnić, zwłaszcza na stronach logowania i w panelu administracyjnym, i oznacz każdego dostawcę, którego domena wygląda na porzuconą.
- Zrób lokalną kopię plików, za które jesteś gotów odpowiadać i które będziesz ponownie przeglądać. Przypnij każdy skrypt, który zostaje: wygeneruj hashe SHA-384, dodaj
integrityorazcrossorigin="anonymous"i przetestuj na stagingu. - Wdróż
Integrity-Policy-Report-Onlydla skryptów i czytaj raporty. Włącz egzekwowanieIntegrity-Policydopiero wtedy, gdy każdy skrypt na stronie ma atrybutintegrity, a strony z tag managerem zostaw w trybie report-only. - Przetestuj na stagingu
Content-Security-Policyzscript-srciobject-src 'none', ponieważ blokuje ona skrypty inline. Ogranicz krąg osób, które mogą publikować w Twoim tag managerze. Do niezależnej weryfikacji test penetracyjny może objąć te strony.
