Content Security Policy a Twój CMP: jak pogodzić CSP ze zgodą
Dwie warstwy bezpieczeństwa, które muszą się zgadzać
Content Security Policy (CSP) mówi przeglądarce, z jakich źródeł strona może ładować skrypty, style, obrazy, ramki i żądania sieciowe. Platforma zarządzania zgodami robi coś odwrotnego: decyduje, które z tych skryptów mogą działać, zależnie od wyboru użytkownika. Gdy skonfiguruje się je osobno, kolidują. CMP nie ładuje się, bo blokuje go CSP, albo CSP zostaje tak poluzowana na potrzeby CMP i tagów reklamowych, że przestaje cokolwiek chronić.
Ten przewodnik wyjaśnia, jakich dyrektyw CSP zwykle potrzebuje CMP, jak nonce współgrają z wstrzykiwaniem skryptów i jak wdrażać zmiany bez psucia banera.
Czego CMP zwykle potrzebuje od CSP
Dokładne wymagania zależą od dostawcy, więc zawsze zaczynaj od dokumentacji własnego CMP. Ogólnie sprawdź te dyrektywy:
script-src— domena, z której ładuje się skrypt CMP, plus wszelkie dodatkowe pliki skryptów, które ładuje.connect-src— punkty końcowe wywoływane przez CMP za pomocąfetchlub XHR, takie jak konfiguracja, lista dostawców, geolokalizacja i rejestrowanie zgód.style-src— domena arkuszy stylów i ewentualnie style inline, jeśli CMP wstrzykuje element<style>lub ustawia atrybuty style.img-src— logo, ikony i wszelkie piksele bez śledzenia, których używa CMP.font-src— jeśli baner ładuje własne czcionki.frame-src— jeśli CMP używa ramek iframe, na przykład do współdzielenia zgody między domenami.
W witrynach z TCF pamiętaj, że CMP tworzy na stronie także ramkę lokalizującą o nazwie __tcfapiLocator. Ramka ta jest tworzona bez zdalnego źródła, więc zwykle nie wymaga wpisu w frame-src, ale warto to potwierdzić w testach.
Problem inline stuba
Większość CMP prosi o umieszczenie w nagłówku strony małego skryptu inline — stuba — aby inne skrypty mogły kolejkować wywołania przed załadowaniem głównego CMP. Restrykcyjna CSP blokuje skrypty inline, o ile ich wyraźnie nie dopuścisz. Masz trzy opcje:
- Nonce. Generuj losową wartość dla każdej odpowiedzi, dodaj ją do nagłówka CSP jako
'nonce-...'i do znacznika<script>stuba. To najbardziej elastyczna opcja dla stron dynamicznych. - Hash. Dodaj do
script-srcskrót SHA-256 dokładnej zawartości stuba. Dobrze działa w witrynach statycznych, ale każda zmiana stuba, nawet w białych znakach, go psuje. - Samodzielne hostowanie stuba jako zewnętrznego pliku na własnej domenie, objętego
'self'. Wymaga to dbałości, by ładował się wystarczająco wcześnie.
Unikaj 'unsafe-inline' jako skrótu. Dopuszcza każdy skrypt inline, co usuwa znaczną część ochrony zapewnianej przez CSP.
Nonce i skrypty wstrzykiwane przez CMP
CMP blokujący skrypty do czasu zgody często działa tak, że wstrzymuje je i wstrzykuje później. Przy CSP opartej na nonce te wstrzyknięte skrypty też trzeba dopuścić. Są dwa typowe podejścia:
- Propagacja nonce. CMP odczytuje nonce z własnego znacznika skryptu i dodaje go do każdego wstrzykiwanego skryptu. Sprawdź, czy Twój CMP to obsługuje.
'strict-dynamic'. To słowo kluczowe nakazuje obsługującym je przeglądarkom ufać skryptom ładowanym przez skrypt, któremu już zaufano. Upraszcza życie z menedżerami tagów i CMP wstrzykującymi skrypty, ale oznacza też, że każdy skrypt, któremu ufasz, może ładować kolejne, więc ufaj ostrożnie.
To samo pytanie nasuwają menedżery tagów. Jeśli ładujesz tagi reklamowe i analityczne przez menedżera tagów, postępuj zgodnie z jego dokumentacją dotyczącą nonce i upewnij się, że CMP i menedżer tagów stosują spójne podejście.
Tagi reklamowe utrudniają CSP
Reklama programatyczna ładuje skrypty i ramki z wielu domen, a lista zmienia się wraz ze zmianą partnerów popytowych. Wydawcy zwykle wybierają jedno z dwojga:
- Restrykcyjną CSP na stronach bez reklam programatycznych i szerszą politykę tam, gdzie reklamy działają.
- Politykę skupioną na dyrektywach, które pozostają możliwe do opanowania, takich jak
frame-ancestors,object-src 'none'ibase-uri, przy czym źródła skryptów pozostają szersze.
Tak czy inaczej CMP powinien znajdować się na jawnej liście dozwolonych, a nie być objęty wyłącznie symbolem wieloznacznym, aby zmiana CSP nigdy po cichu nie wyłączyła banera.
Wdrażaj w trybie Report-Only
Najpierw użyj nagłówka Content-Security-Policy-Report-Only. Przeglądarka zgłasza naruszenia, niczego nie blokując, dzięki czemu widzisz, co nowa polityka by zepsuła.
- Wdróż politykę w trybie report-only z punktem końcowym raportowania.
- Ładuj strony w czystych profilach przeglądarki i przejdź cały przepływ zgody: pierwsza wizyta, akceptuj wszystko, odrzuć wszystko, własny wybór, wycofanie.
- Przejrzyj raporty o naruszeniach i konsolę przeglądarki pod kątem zablokowanych zasobów CMP.
- Dostosuj politykę, a następnie przełącz na egzekwowanie.
- Po przejściu na egzekwowanie zostaw raportowanie włączone, by wychwytywać regresje.
Objawy konfliktu z CSP
- Baner nigdy się nie pojawia, a konsola pokazuje naruszenie CSP dla skryptu CMP.
- Baner się pojawia, ale bez stylów, bo
style-srcblokuje jego CSS. - Wybory nie są zapisywane, bo
connect-srcblokuje wywołanie rejestrujące zgodę. - Reklamy lub analityka nigdy się nie ładują po zgodzie, bo wstrzykniętym skryptom brakuje nonce.
__tcfapijest niezdefiniowane, bo inline stub został zablokowany.
Najważniejsze wnioski
- Sprawdź
script-src,connect-src,style-src,img-srciframe-srcdla swojego CMP. - Inline stub dopuść za pomocą nonce lub hasha, a nie
'unsafe-inline'. - Upewnij się, że skrypty wstrzykiwane po zgodzie dostają nonce albo są objęte
'strict-dynamic'. - Przetestuj każdą ścieżkę zgody w trybie report-only przed egzekwowaniem.
- Trzymaj CMP jawnie na liście dozwolonych, aby zmiany CSP nie mogły go wyłączyć.