LW IT Solutions
« Blog Overview /Data Privacy/Tutorials / Utwardzanie infrastruktury internetowej: Kontrola obcych skryptów za...
This post in other languages:

Utwardzanie infrastruktury internetowej: Kontrola obcych skryptów za pomocą Content Security Policy (CSP)

Utwardzanie infrastruktury internetowej: Kontrola obcych skryptów za pomocą Content Security Policy (CSP)
Spis treści
  1. Przegląd architektury: Wektory ataków poprzez wstrzykiwanie obcych skryptów
  2. Instrukcja wdrożenia krok po kroku
  3. Podsumowanie i mierzalna wartość dodana
  4. Pytania i odpowiedzi
  5. Źródła

Przegląd architektury: Wektory ataków poprzez wstrzykiwanie obcych skryptów

Współczesne aplikacje internetowe i instalacje WordPressa regularnie korzystają ze skryptów JavaScript firm trzecich do analizy ruchu, zarządzania tagami, obsługi mediów i automatyzacji marketingu. Każde zewnętrzne źródło kodu wprowadzone do struktury Document Object Model (DOM) poszerza jednak powierzchnię ataku. Przejęte sieci dostarczania treści (CDN), ataki typu supply-chain na biblioteki JavaScript lub złośliwe rozszerzenia przeglądarek mogą niepostrzeżenie wstrzykiwać nieautoryzowane skrypty do aktywnej sesji użytkownika.

W przypadku braku architektonicznych zabezpieczeń na poziomie nagłówków HTTP, przeglądarki bezwarunkowo wykonują każdy skrypt obecny w drzewie DOM. Stwarza to poważne ryzyko ataków Cross-Site Scripting (XSS), skrapowania struktury DOM oraz nieautoryzowanej eksfiltracji danych (np. kradzieży ciasteczek lub wyłudzania danych z formularzy). Wdrożenie rygorystycznej polityki Content Security Policy (CSP) ustanawia niezmienny system zezwoleń w przeglądarce klienta, gwarantując, że kod mogą wykonywać wyłącznie jawnie zdefiniowane domeny i zweryfikowane skróty kryptograficzne.

Przebieg Content Security Policy: nagłówek z Nginxa i WordPressa, oceniany przez przeglądarkę na zasoby dozwolone i zablokowane
Jak działa polityka: nagłówek pochodzi z Nginxa, WordPress służy jako zapas. Przeglądarka porównuje następnie każdy zasób z dyrektywami — googletagmanager.com jest na liście dozwolonych, wstrzyknięte skrypty i osadzenia object nie.

Instrukcja wdrożenia krok po kroku

Krok 1: Przeprowadzenie pełnego audytu skryptów i punktów końcowych

Przed wdrożeniem blokującego nagłówka CSP konieczne jest skatalogowanie wszystkich uzasadnionych zależności domenowych. W standardowym środowisku WordPress v7.0.2 wyposażonym w zaawansowane zarządzanie tagami i analitykę server-side, audyt wykazuje zazwyczaj następujące kluczowe dyrektywy:

  • default-src 'self' – Ogranicza ładowanie zasobów domyślnych wyłącznie do domeny głównej.
  • script-src 'self' – Zezwala na wykonywanie skryptów hostowanych na własnym serwerze.
  • connect-src 'self' – Ogranicza połączenia REST API, Fetch i XHR do zaufanych punktów analitycznych.
  • img-src 'self' data: – Dopuszcza ładowanie lokalnych grafik i osadzonych schematów URI base64.

Krok 2: Projektowanie polityki CSP o minimalnych uprawnieniach

W celu zablokowania obcych skryptów śledzących przy jednoczesnym zachowaniu sprawności autoryzowanych systemów (takich jak Google Tag Manager, GA4, Matomo lub własny punkt końcowy Server-Side GTM), należy precyzyjnie określić białe listy domen. Bezpieczna polityka bazowa dla środowisk analitycznych wygląda następująco:

default-src 'self';
script-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://cdn.matomo.cloud;
img-src 'self' data: https://www.google-analytics.com https://www.googletagmanager.com;
connect-src 'self' https://www.google-analytics.com https://region1.google-analytics.com https://matomo.cloud https://tracking.lukaswojcik.com;
frame-src 'self' https://www.youtube.com;
object-src 'none';
base-uri 'self';
form-action 'self';

Uwaga: Stosowanie parametru 'unsafe-inline' w dyrektywie script-src powinno w środowiskach o najwyższym rygorze bezpieczeństwa zostać zastąpione przez kryptograficzne wartości nonce lub skróty SHA-256.

Krok 3: Wdrożenie na poziomie serwera w konfiguracji Nginx

Ze względów wydajnościowych nagłówki CSP powinny być wysyłane bezpośrednio przez serwer WWW, a nie generowane w warstwie aplikacji PHP. Umieszczenie polityki w bloku serwera SSL programu Nginx zapewnia jej natychmiastowe egzekwowanie przed przetworzeniem kodu PHP:

# /etc/nginx/sites-available/lukaswojcik.com.conf
server {
    listen 443 ssl http2;
    server_name www.lukaswojcik.com lukaswojcik.com;

    # Wymuszenie rygorystycznego nagłówka CSP
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://cdn.matomo.cloud; img-src 'self' data: https://www.google-analytics.com https://www.googletagmanager.com; connect-src 'self' https://www.google-analytics.com https://region1.google-analytics.com https://matomo.cloud https://tracking.lukaswojcik.com; frame-src 'self' https://www.youtube.com; object-src 'none'; base-uri 'self'; form-action 'self';" always;
    
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
}

Po modyfikacji konfiguracji serwera Nginx wymagane jest sprawdzenie składni oraz bezkolizyjne przeładowanie usługi:

nginx -t && systemctl reload nginx

Krok 4: Zabezpieczenie na poziomie aplikacji przez functions.php

W przypadku braku dostępu administracyjnego do konfiguracji serwera Nginx, identyczny nagłówek CSP może być wysyłany za pośrednictwem PHP podczas cyklu żądania WordPressa poprzez wdrożenie poniższego kodu do pliku functions.php aktywnego motywu:

/**
 * Wdrożenie nagłówka Content Security Policy
 * Cel: WordPress v7.0.2
 */
add_action( 'send_headers', 'lw_enforce_content_security_policy' );

function lw_enforce_content_security_policy() {
    if ( ! is_admin() ) {
        $csp = "default-src 'self'; " .
               "script-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://cdn.matomo.cloud; " .
               "img-src 'self' data: https://www.google-analytics.com https://www.googletagmanager.com; " .
               "connect-src 'self' https://www.google-analytics.com https://region1.google-analytics.com https://matomo.cloud https://tracking.lukaswojcik.com; " .
               "frame-src 'self' https://www.youtube.com; " .
               "object-src 'none'; " .
               "base-uri 'self'; " .
               "form-action 'self';";
        
        header( 'Content-Security-Policy: ' . $csp );
    }
}

Krok 5: Kontrola jakości i testowanie w trybie Report-Only

Przed wdrożeniem reguł blokujących w środowisku produkcyjnym zaleca się tymczasowe zastosowanie nagłówka Content-Security-Policy-Report-Only. Pozwala to na rejestrowanie naruszeń w konsoli przeglądarki bez wstrzymywania wykonywania skryptów.

Weryfikację należy przeprowadzić przy użyciu narzędzi deweloperskich (F12):

  1. Weryfikacja nagłówka sieciowego: Otwarcie zakładki Network, odświeżenie widoku strony i potwierdzenie obecności kompletnego ciągu Content-Security-Policy w odpowiedzi HTTP.
  2. Wykrywanie anomalii w konsoli: Monitoring zakładki Console. Nieautoryzowane skrypty śledzące natychmiast wygenerują czerwone komunikaty o błędach CSP. Skrypty treści (content scripts) rozszerzeń przeglądarki nie podlegają natomiast polityce CSP strony; sprawdzane jest tylko to, co wstawiają do strony jako elementy script.
  3. Walidacja punktów śledzących: Sprawdzenie, czy zapytania analityczne kierowane do własnej subdomeny server-side zwracają kod HTTP 200 bez blokad ze strony mechanizmów bezpieczeństwa.

Podsumowanie i mierzalna wartość dodana

Co da się osiągnąć dzięki instrukcji: Niekontrolowane wykonywanie dowolnych skryptów JavaScript w drzewie DOM zostaje zastąpione przez kryptograficznie egzekwowaną listę zaufanych domen, zarządzaną bezpośrednio przez silnik bezpieczeństwa przeglądarki.

Wynikająca z tego wartość dodana:

  • Ochrona przed atakami Supply-Chain: Złamane zewnętrzne biblioteki JavaScript oraz obce skrypty są natychmiast blokowane przed uruchomieniem lub próbą eksfiltracji danych.
  • Zgodność z RODO i wymogami prywatności: Nieautoryzowane piksele śledzące oraz tagi doczepiane są systemowo wstrzymywane przed nawiązaniem połączeń z zewnętrznymi sieciami reklamowymi.
  • Zabezpieczenie formularzy i sesji: Ograniczenia dyrektyw connect-src oraz form-action uniemożliwiają przechwytywanie danych wejściowych z formularzy na wszystkich podstronach WordPressa.

Pytania i odpowiedzi

Dlaczego na niektórych adresach brakuje CSP z konfiguracji Nginx?

Z powodu zasady dziedziczenia add_header. Nginx przenosi dyrektywy add_header z bloku server tylko do tych bloków location, które same nie zawierają żadnej dyrektywy add_header. Jeśli blok location dla obrazów, czcionek albo PHP ustawia własny nagłówek, na przykład Cache-Control, znikają w nim wszystkie nagłówki z bloku server, łącznie z Content-Security-Policy, X-Content-Type-Options i X-Frame-Options.

Często długo pozostaje to niezauważone, bo kontrola z kroku 5 odbywa się zwykle na stronie HTML. Bezpieczniejsza jest próbka dla każdego bloku location, obejmująca także obrazy, skrypty i adresy obsługiwane przez PHP.

Rozwiązaniem jest powtórzenie nagłówków w każdym bloku location, który ma własne wiersze add_header, najprościej przez wspólny plik dołączany dyrektywą include.

Co się dzieje, gdy CSP wysyłają jednocześnie Nginx i functions.php?

Obowiązują wtedy obie polityki. Przeglądarka nie scala kilku nagłówków Content-Security-Policy w jedną politykę, lecz sprawdza każdy zasób względem każdej z nich, a ładuje tylko to, na co zezwalają wszystkie. Domena wpisana tylko w jednej z dwóch wersji pozostaje więc zablokowana. Łatwo o to, gdy źródło zostaje dopisane tylko w jednym miejscu, na przykład w konfiguracji Nginx, ale nie w functions.php.

Z drugiej strony może zabraknąć nagłówka z functions.php, choć kod jest poprawny. Pamięć podręczna stron, która wydaje gotowe pliki HTML bezpośrednio z serwera WWW bez uruchamiania PHP, dostarcza je bez tego nagłówka, o ile nie zapisuje razem z nimi nagłówków. Przy ustawianiu polityki przez PHP warto więc sprawdzić także stronę wydaną z pamięci podręcznej, a nie tylko świeżo wygenerowaną.

Jak zbierać naruszenia, które występują tylko u prawdziwych odwiedzających?

Przez adres zgłoszeń w polityce. Konsola pokazuje naruszenia tylko w przeglądarce osoby, która akurat sprawdza; z dyrektywą report-uri albo nowszą report-to razem z nagłówkiem Reporting-Endpoints przeglądarki odwiedzających wysyłają każde naruszenie jako JSON do punktu końcowego prowadzonego przez witrynę, także w trybie Report-Only. Takie zgłoszenia zawierają też szum, na przykład z rozszerzeń przeglądarki, dlatego warto analizować je według źródła, a nie patrzeć tylko na ich liczbę.

Lukas Wójcik

Lukas Wójcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Get in Touch

Briefly describe your project or inquiry for a tailored response. This site is protected by reCAPTCHA.

Napisanie komentarza

Obserwacje z innych wdrożeń, zastrzeżenia i pytania są tu mile widziane.

Adres e-mail nie jest publikowany. Pola obowiązkowe oznaczono gwiazdką.

ALL ARTICLES & CATEGORIES

CCTV

Śledź tę kategorię przez RSS

Cloud & AI

Śledź tę kategorię przez RSS

Data Privacy

Wszystkie artykuły w tej kategorii (17) Śledź tę kategorię przez RSS

Digital Analytics

Wszystkie artykuły w tej kategorii (54) Śledź tę kategorię przez RSS

Digital Marketing

Wszystkie artykuły w tej kategorii (36) Śledź tę kategorię przez RSS

IT & Networks

Wszystkie artykuły w tej kategorii (17) Śledź tę kategorię przez RSS

Music Production

Wszystkie artykuły w tej kategorii (14) Śledź tę kategorię przez RSS

Raspberry Pi

Śledź tę kategorię przez RSS

Smart Home

Wszystkie artykuły w tej kategorii (18) Śledź tę kategorię przez RSS

Tworzenie stron internetowych

Wszystkie artykuły w tej kategorii (11) Śledź tę kategorię przez RSS

Wtyczki i triki WordPress

Śledź tę kategorię przez RSS