---
title: "CSP dla usług Google: GTM, GA4, Maps, Fonts (przewodnik 2026)"
description: "Kompletny przewodnik po konfiguracji Content-Security-Policy dla GTM, GA4, Google Maps, Fonts, reCAPTCHA, YouTube i Ads. Gotowe przykłady, nonce + strict-dynamic, Consent Mode v2 oraz rozwiązywanie najczęstszych błędów."
date: 2026-01-06
updated: 2026-04-19
category: Bezpieczeństwo
tags: ["CSP", "Content-Security-Policy", "Bezpieczeństwo", "GTM", "GA4", "Google Maps"]
url: https://uper.pl/blog/csp-google-services/
---

# CSP dla usług Google — jak skonfigurować Content-Security-Policy dla GTM, GA4, Maps, Fonts i innych

**Content-Security-Policy (CSP)** to nagłówek HTTP, który chroni witrynę przed atakami XSS i innymi zagrożeniami. Zbyt restrykcyjna polityka potrafi jednak zablokować usługi Google — GTM, Analytics czy Maps. Ten przewodnik pokazuje, jak skonfigurować CSP tak, aby wszystkie potrzebne usługi działały.

## TL;DR — gotowy nagłówek CSP dla typowej strony

Jeśli potrzebujesz od razu działającego nagłówka CSP dla witryny z GTM, GA4, Google Maps, Fonts, reCAPTCHA i YouTube, zacznij od tego i dostosuj:

```http
Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-RANDOM' 'strict-dynamic'
    https://www.googletagmanager.com
    https://www.google-analytics.com
    https://maps.googleapis.com
    https://www.google.com/recaptcha/
    https://www.gstatic.com/recaptcha/;
  style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
  font-src 'self' https://fonts.gstatic.com;
  img-src 'self' data: blob:
    https://*.google-analytics.com
    https://*.googletagmanager.com
    https://*.gstatic.com
    https://*.googleapis.com
    https://*.ggpht.com
    https://i.ytimg.com;
  connect-src 'self'
    https://*.google-analytics.com
    https://*.analytics.google.com
    https://*.googletagmanager.com
    https://stats.g.doubleclick.net
    https://maps.googleapis.com;
  frame-src
    https://www.googletagmanager.com
    https://www.google.com
    https://www.youtube.com
    https://www.youtube-nocookie.com;
  worker-src 'self' blob:;
  object-src 'none';
  base-uri 'self';
  form-action 'self';
```

Zastąp `RANDOM` noncem generowanym per-request po stronie serwera. Zanim włączysz egzekwowanie, uruchom politykę w trybie `Content-Security-Policy-Report-Only`, żeby zobaczyć, co Twoja prawdziwa strona faktycznie ładuje.

## Czym jest Content-Security-Policy?

**CSP** definiuje dozwolone źródła dla różnych typów zasobów (skrypty, style, obrazy, fonty). Przeglądarka blokuje wszystko, co nie jest jawnie dozwolone.

### Podstawowa składnia

```http
Content-Security-Policy: dyrektywa źródło1 źródło2; dyrektywa2 źródło3;
```

### Główne dyrektywy

| Dyrektywa | Kontroluje |
|-----------|------------|
| `default-src` | Domyślne źródło dla wszystkich typów |
| `script-src` | Skrypty JavaScript |
| `style-src` | Style CSS |
| `img-src` | Obrazy |
| `font-src` | Fonty |
| `connect-src` | XHR, fetch, WebSocket |
| `frame-src` | Iframes |
| `object-src` | Pluginy (Flash, Java) |

### Wartości źródeł

| Wartość | Znaczenie |
|---------|-----------|
| `'self'` | Ta sama domena |
| `'none'` | Blokuj wszystko |
| `'unsafe-inline'` | Dozwól inline (niebezpieczne!) |
| `'unsafe-eval'` | Dozwól eval() (niebezpieczne!) |
| `'nonce-xyz'` | Tylko skrypty z tym nonce |
| `'strict-dynamic'` | Zaufaj skryptom ładowanym przez zaufane |
| `https:` | Wszystkie źródła HTTPS |
| `*.example.com` | Subdomena |

## CSP dla Google Tag Manager

GTM wymaga wielu domen i funkcjonalności. Konfiguracja zależy od trybu (client-side vs server-side).

### GTM client-side — minimalna konfiguracja

```http
Content-Security-Policy:
  script-src 'self' 'unsafe-inline' 'unsafe-eval'
    https://www.googletagmanager.com
    https://tagmanager.google.com;
  img-src 'self' data:
    https://www.googletagmanager.com
    https://www.google-analytics.com
    https://ssl.gstatic.com
    https://www.gstatic.com;
  connect-src 'self'
    https://www.google-analytics.com
    https://analytics.google.com
    https://stats.g.doubleclick.net
    https://region1.google-analytics.com;
  frame-src
    https://www.googletagmanager.com;
```

### Problem: GTM wymaga unsafe-inline i unsafe-eval

GTM dynamicznie wstrzykuje skrypty, co wymaga `'unsafe-inline'`. Tagi Custom HTML mogą używać `eval()`. To znacząco osłabia CSP.

### Rozwiązanie 1: nonce dla GTM

```html
<!-- Generuj nonce po stronie serwera -->
<script nonce="abc123">
  (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
  new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
  j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;
  j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;
  j.nonce='abc123';
  f.parentNode.insertBefore(j,f);
  })(window,document,'script','dataLayer','GTM-XXXXX');
</script>
```

```http
Content-Security-Policy:
  script-src 'self' 'nonce-abc123' 'strict-dynamic'
    https://www.googletagmanager.com;
```

### Rozwiązanie 2: server-side GTM

[Server-side GTM](/blog/gtm-server-side-vs-client-side/) znacząco upraszcza CSP:

```http
Content-Security-Policy:
  script-src 'self' 'nonce-abc123'
    https://gtm.twojadomena.pl;
  connect-src 'self'
    https://gtm.twojadomena.pl;
```

## CSP dla Google Analytics 4

### GA4 z gtag.js

```http
Content-Security-Policy:
  script-src 'self'
    https://www.googletagmanager.com;
  img-src 'self'
    https://www.google-analytics.com
    https://www.googletagmanager.com;
  connect-src 'self'
    https://www.google-analytics.com
    https://analytics.google.com
    https://region1.google-analytics.com
    https://region2.google-analytics.com
    https://region3.google-analytics.com;
```

### GA4 przez GTM

Jeśli ładujesz GA4 przez GTM, potrzebujesz kombinacji powyższych reguł. Zobacz też [dobre praktyki dataLayer](/blog/datalayer-best-practices/) — poprawnie zaprojektowany dataLayer pozwala ograniczyć liczbę Custom HTML tagów, co bezpośrednio upraszcza politykę CSP.

## CSP dla Google Maps

### Maps JavaScript API

```http
Content-Security-Policy:
  script-src 'self' 'unsafe-inline'
    https://maps.googleapis.com
    https://maps.gstatic.com;
  img-src 'self' data: blob:
    https://maps.googleapis.com
    https://maps.gstatic.com
    https://*.ggpht.com
    https://*.google.com
    https://*.googleapis.com;
  style-src 'self' 'unsafe-inline'
    https://fonts.googleapis.com;
  font-src 'self'
    https://fonts.gstatic.com;
  connect-src 'self'
    https://maps.googleapis.com
    https://places.googleapis.com;
  frame-src
    https://www.google.com;
  worker-src blob:;
```

### Maps Embed API (iframe)

```http
Content-Security-Policy:
  frame-src
    https://www.google.com
    https://maps.google.com;
```

## CSP dla Google Fonts

```http
Content-Security-Policy:
  style-src 'self'
    https://fonts.googleapis.com;
  font-src 'self'
    https://fonts.gstatic.com;
```

### Alternatywa: self-hosting fontów

Hostując fonty lokalnie, eliminujesz zewnętrzne zależności:

```http
Content-Security-Policy:
  font-src 'self';
  style-src 'self';
```

## CSP dla Google reCAPTCHA

### reCAPTCHA v2/v3

```http
Content-Security-Policy:
  script-src 'self'
    https://www.google.com/recaptcha/
    https://www.gstatic.com/recaptcha/;
  frame-src
    https://www.google.com/recaptcha/
    https://recaptcha.google.com;
  style-src 'self' 'unsafe-inline';
```

## CSP dla osadzeń YouTube

```http
Content-Security-Policy:
  frame-src
    https://www.youtube.com
    https://www.youtube-nocookie.com;
  img-src 'self'
    https://i.ytimg.com
    https://img.youtube.com;
```

### Pułapka 1: sam youtube-nocookie.com nie wystarczy

Wiele stron używa `youtube-nocookie.com` ze względu na prywatność — i dodaje do whitelisty **tylko** tę domenę w `frame-src`. To rozbija embed w kilku sytuacjach:

- **Overlay z polecanymi filmami** na końcu klipu przekierowuje na `youtube.com`.
- **Linki do kanału i logo** w pasku playera otwierają `youtube.com`.
- **Część zasobów chrome playera** i tak ładuje się z `youtube.com` niezależnie od tego, którą domenę osadzasz.

**Rozwiązanie:** zawsze dodawaj do whitelisty zarówno `https://www.youtube-nocookie.com`, jak i `https://www.youtube.com` w `frame-src`, nawet jeśli Twój `<iframe src>` wskazuje tylko na wersję bez cookies.

### Pułapka 2: domeny miniaturek dla lite-embeds

Jeśli używasz wzorca "facade" (klikalna miniatura zamiast pełnego iframe) — popularne rozwiązanie dla wydajności — obrazek miniatury ładuje się z innej domeny niż sam player:

- `https://i.ytimg.com` — domyślny host miniaturek (`vi/VIDEO_ID/maxresdefault.jpg`).
- `https://img.youtube.com` — starszy alias, wciąż używany przez niektóre biblioteki.

Obie muszą być w `img-src`, inaczej podgląd po cichu się nie załaduje i użytkownik zobaczy pusty placeholder.

### Pułapka 3: Cross-Origin-Opener-Policy łamie YouTube

Jeśli zabezpieczasz witrynę nagłówkiem `Cross-Origin-Opener-Policy: same-origin`, iframe YouTube traci dostęp do popupów, które otwiera (logowanie, udostępnianie, full-screen). Player sprawia wrażenie, że działa, ale niektóre interakcje po cichu zawodzą i nie widać żadnego błędu CSP w konsoli. **Rozwiązanie:** przełącz na `Cross-Origin-Opener-Policy: same-origin-allow-popups`.

Po pełne wyjaśnienie COOP, COEP, CORP, `crossOriginIsolated` oraz jak odblokować `SharedArrayBuffer` bez łamania integracji third-party zobacz dedykowany przewodnik: [COOP, COEP, CORP — cross-origin isolation po polsku](/blog/coop-coep-corp-cross-origin-isolation/).

### Gotowa produkcyjna konfiguracja

Oto dokładny fragment, którego używamy na uper.pl — łączy GTM + GA4 + osadzenia YouTube w trybie no-cookie w jednym nagłówku:

```http
Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'unsafe-inline' 'unsafe-eval'
    https://www.googletagmanager.com
    https://tagmanager.google.com;
  style-src 'self' 'unsafe-inline'
    https://cdn.jsdelivr.net;
  font-src 'self'
    https://cdn.jsdelivr.net;
  img-src 'self' data:
    https://www.googletagmanager.com
    https://www.google-analytics.com
    https://ssl.gstatic.com
    https://www.gstatic.com
    https://i.ytimg.com;
  connect-src 'self'
    https://www.google-analytics.com
    https://analytics.google.com
    https://stats.g.doubleclick.net
    https://*.google-analytics.com
    https://*.analytics.google.com
    https://*.googletagmanager.com;
  frame-src
    https://www.googletagmanager.com
    https://www.youtube-nocookie.com
    https://www.youtube.com;
  object-src 'none';
  base-uri 'self';
  form-action 'self';
  frame-ancestors 'self';
```

W parze z `Cross-Origin-Opener-Policy: same-origin-allow-popups` oraz `X-Frame-Options: SAMEORIGIN` ta kombinacja przechodzi audyt Mozilla Observatory z oceną A+, a osadzenia YouTube działają bez zarzutu.

## CSP dla Google Ads

### Google Ads — śledzenie konwersji

```http
Content-Security-Policy:
  script-src 'self' 'unsafe-inline'
    https://www.googleadservices.com
    https://www.googletagmanager.com
    https://googleads.g.doubleclick.net;
  img-src 'self'
    https://www.google.com
    https://www.google.pl
    https://googleads.g.doubleclick.net
    https://www.googleadservices.com;
  connect-src 'self'
    https://www.google.com
    https://pagead2.googlesyndication.com;
  frame-src
    https://bid.g.doubleclick.net
    https://tpc.googlesyndication.com;
```

### Google AdSense

```http
Content-Security-Policy:
  script-src 'self' 'unsafe-inline' 'unsafe-eval'
    https://pagead2.googlesyndication.com
    https://adservice.google.com
    https://www.googletagservices.com
    https://partner.googleadservices.com;
  img-src 'self' data:
    https://pagead2.googlesyndication.com
    https://tpc.googlesyndication.com
    https://*.google.com;
  frame-src
    https://googleads.g.doubleclick.net
    https://tpc.googlesyndication.com
    https://www.google.com;
  style-src 'self' 'unsafe-inline';
```

## CSP dla Google Consent Mode v2

**Consent Mode v2** jest obowiązkowy dla ruchu z UE od marca 2024. Używa tych samych domen co GTM + GA4, ale wprowadza dwa niuanse:

1. **Cookiebot, Iubenda, OneTrust i inne CMP** ładują się z własnych domen — dodaj do whitelisty tę, której używasz.
2. **Sygnały zgody są wysyłane, zanim użytkownik wyrazi zgodę** (w stanie `denied`), więc `connect-src` do Google musi być otwarty od pierwszego wejścia na stronę, a nie dopiero po akceptacji.

```http
Content-Security-Policy:
  script-src 'self' 'nonce-abc123'
    https://www.googletagmanager.com
    https://consent.cookiebot.com
    https://consentcdn.cookiebot.com;
  connect-src 'self'
    https://consent.cookiebot.com
    https://consentcdn.cookiebot.com
    https://www.google-analytics.com
    https://region1.google-analytics.com;
  frame-src
    https://consent.cookiebot.com
    https://consentcdn.cookiebot.com;
```

Zobacz [przewodnik wdrażania Consent Mode v2](/blog/google-consent-mode-v2/) oraz [jak zweryfikować, że działa poprawnie](/blog/jak-zweryfikowac-google-consent-mode-v2/).

## CSP dla Google Identity Services (GIS) / One Tap

Google Identity Services zastąpiły starą bibliotekę `gapi.auth2`. Logowanie Google, One Tap oraz FedCM API używają tych domen:

```http
Content-Security-Policy:
  script-src 'self'
    https://accounts.google.com/gsi/client;
  connect-src 'self'
    https://accounts.google.com/gsi/
    https://accounts.google.com/.well-known/;
  frame-src
    https://accounts.google.com/gsi/
    https://accounts.google.com/o/oauth2/;
  style-src 'self' 'unsafe-inline'
    https://accounts.google.com/gsi/style;
```

> **Typowa pułapka:** FedCM wymaga `frame-ancestors` po stronie Google, nie Twojej. Jeśli One Tap po cichu się nie renderuje, sprawdź `accounts.google.com` w zakładce Network — błąd 403 zwykle oznacza, że Twoja strona nie znajduje się w authorized origins klienta OAuth w Google Cloud, a nie problem z CSP.

## CSP dla Firebase (Auth, Firestore, Hosting)

Firebase obejmuje kilka usług Google. Każdy produkt wymaga własnego zestawu wpisów:

```http
Content-Security-Policy:
  script-src 'self'
    https://www.gstatic.com/firebasejs/
    https://apis.google.com
    https://www.googleapis.com;
  connect-src 'self'
    https://*.firebaseio.com
    https://*.firebaseapp.com
    https://firestore.googleapis.com
    https://identitytoolkit.googleapis.com
    https://securetoken.googleapis.com
    wss://*.firebaseio.com;
  frame-src
    https://*.firebaseapp.com;
```

Firebase Auth używa `signInWithRedirect`, który otwiera `__/auth/handler` na Twojej subdomenie Firebase Hosting — pamiętaj, aby dodać ją do `frame-src`.

## Kompletna konfiguracja dla typowej witryny

### Strona z GTM, GA4, Maps i Fonts

```http
Content-Security-Policy:
  default-src 'self';

  script-src 'self' 'unsafe-inline' 'unsafe-eval'
    https://www.googletagmanager.com
    https://tagmanager.google.com
    https://www.google-analytics.com
    https://maps.googleapis.com
    https://maps.gstatic.com;

  style-src 'self' 'unsafe-inline'
    https://fonts.googleapis.com
    https://tagmanager.google.com;

  img-src 'self' data: blob:
    https://www.googletagmanager.com
    https://www.google-analytics.com
    https://ssl.gstatic.com
    https://www.gstatic.com
    https://maps.googleapis.com
    https://maps.gstatic.com
    https://*.ggpht.com
    https://*.google.com;

  font-src 'self'
    https://fonts.gstatic.com;

  connect-src 'self'
    https://www.google-analytics.com
    https://analytics.google.com
    https://region1.google-analytics.com
    https://stats.g.doubleclick.net
    https://maps.googleapis.com;

  frame-src
    https://www.googletagmanager.com
    https://www.google.com
    https://www.youtube.com;

  object-src 'none';
  base-uri 'self';
  form-action 'self';
```

## Implementacja CSP

### Apache (.htaccess)

```apache
Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://www.googletagmanager.com; ..."
```

### Nginx

```nginx
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://www.googletagmanager.com; ..." always;
```

### Node.js (Express)

```javascript
const helmet = require('helmet');

app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: ["'self'", "https://www.googletagmanager.com"],
    styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
    imgSrc: ["'self'", "data:", "https://www.google-analytics.com"],
    fontSrc: ["'self'", "https://fonts.gstatic.com"],
    connectSrc: ["'self'", "https://www.google-analytics.com"],
    frameSrc: ["https://www.googletagmanager.com"]
  }
}));
```

### Netlify (netlify.toml)

```toml
[[headers]]
  for = "/*"
  [headers.values]
    Content-Security-Policy = "default-src 'self'; script-src 'self' https://www.googletagmanager.com; ..."
```

### Vercel (vercel.json)

```json
{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "Content-Security-Policy",
          "value": "default-src 'self'; script-src 'self' https://www.googletagmanager.com; ..."
        }
      ]
    }
  ]
}
```

## Testowanie CSP

### 1. Tryb Report-Only

Zacznij od trybu raportowania, który nie blokuje, a jedynie loguje naruszenia:

```http
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report;
```

### 2. DevTools przeglądarki

Konsola pokaże błędy CSP:
```
Refused to load the script 'https://example.com/script.js' because it violates the Content Security Policy directive: "script-src 'self'".
```

### 3. CSP Evaluator

[https://csp-evaluator.withgoogle.com/](https://csp-evaluator.withgoogle.com/) — narzędzie Google do analizy CSP.

### 4. Observatory by Mozilla

[https://observatory.mozilla.org/](https://observatory.mozilla.org/) — kompleksowy audyt bezpieczeństwa.

## Raportowanie naruszeń CSP

### Endpoint raportujący

```http
Content-Security-Policy: default-src 'self'; report-uri /csp-report; report-to csp-endpoint;
```

### Odbieranie raportów (Node.js)

```javascript
app.post('/csp-report', express.json({ type: 'application/csp-report' }), (req, res) => {
  console.log('CSP Violation:', req.body['csp-report']);
  res.status(204).end();
});
```

## Dobre praktyki

### 1. Zacznij restrykcyjnie

```http
Content-Security-Policy: default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self';
```

Dodawaj źródła dopiero gdy są potrzebne.

### 2. Unikaj unsafe-inline i unsafe-eval

Jeśli to możliwe, używaj nonce lub hash zamiast `'unsafe-inline'`:

```html
<script nonce="random123">
  // Twój kod
</script>
```

```http
Content-Security-Policy: script-src 'nonce-random123';
```

### 3. Używaj strict-dynamic

`'strict-dynamic'` pozwala zaufanym skryptom ładować kolejne:

```http
Content-Security-Policy: script-src 'nonce-abc123' 'strict-dynamic';
```

### 4. Rozważ server-side GTM

[Server-side tagging](/blog/gtm-server-side-vs-client-side/) drastycznie upraszcza CSP i zwiększa bezpieczeństwo.

### 5. Regularnie aktualizuj

Google może zmieniać domeny. Monitoruj raporty CSP i aktualizuj politykę.

## Rozwiązywanie problemów — typowe błędy CSP i ich naprawa

Poniżej dokładne komunikaty, które zobaczysz w konsoli DevTools Chrome / Firefox, oraz co dodać do polityki, żeby je naprawić.

### `Refused to load the script 'https://www.googletagmanager.com/gtm.js'`

**Przyczyna:** `script-src` nie zawiera GTM. **Naprawa:** dodaj `https://www.googletagmanager.com` do `script-src`.

### `Refused to apply inline style because it violates the following CSP directive: "style-src 'self'"`

**Przyczyna:** GTM, Google Maps i reCAPTCHA wstrzykują style inline. **Naprawa:** dodaj `'unsafe-inline'` do `style-src` lub użyj nonce, jeśli kontrolujesz wstrzykiwany kod. Hashe rzadko działają, bo style są generowane dynamicznie.

### `Refused to execute inline script because it violates the following CSP directive`

**Przyczyna:** snippet GTM lub dataLayer push jest inline bez nonce. **Opcje naprawy:**

- Dodaj `'unsafe-inline'` do `script-src` (osłabia CSP).
- Dodaj `nonce-xyz` do każdego inline'owego `<script>` ORAZ do `script-src`. W połączeniu z `'strict-dynamic'` nonce pozwala GTM ładować kolejne tagi bez wypisywania wszystkich domen.

### `Refused to connect to 'https://region1.google-analytics.com/g/collect'`

**Przyczyna:** GA4 wysyła hity na regionalne endpointy (`region1`, `region2`, …). **Naprawa:** użyj wildcardu: `https://*.google-analytics.com` w `connect-src`.

### `Refused to load the image 'https://stats.g.doubleclick.net/...'`

**Przyczyna:** GA4 używa DoubleClick do pomiarów cross-site. **Naprawa:** dodaj `https://stats.g.doubleclick.net` do `img-src` i `connect-src`.

### `Refused to create a worker from 'blob:https://...'`

**Przyczyna:** Google Maps używa Web Workers tworzonych z blob URL. **Naprawa:** dodaj `worker-src 'self' blob:` (oraz `blob:` do `script-src`, jeśli korzystasz ze starszego CSP Level 2 bez `worker-src`).

### `Refused to frame 'https://www.google.com/maps/embed'`

**Przyczyna:** Maps Embed używa `frame-src`, nie `img-src`. **Naprawa:** dodaj `https://www.google.com` do `frame-src`.

### reCAPTCHA pokazuje "Cannot contact reCAPTCHA"

**Przyczyna:** zwykle `connect-src` blokuje endpoint challenge'a. **Naprawa:** dodaj `https://www.google.com/recaptcha/` do `script-src` i `frame-src`, oraz `https://www.gstatic.com` do `script-src`.

### Raporty zalewają `report-uri` po wdrożeniu

**Przyczyna:** rozszerzenia przeglądarki (menedżery haseł, blokery reklam) wstrzykują skrypty i generują naruszenia CSP, z którymi nic nie zrobisz. **Naprawa:** filtruj raporty, w których `blocked-uri` zaczyna się od `chrome-extension://`, `moz-extension://` lub `safari-web-extension://`, zanim uruchomią alert.

## Jak bezpiecznie wdrożyć CSP

Wdrożenie strict CSP na działającej witrynie zawsze coś zepsuje — gwarantowane. Trzymaj się tej kolejności:

1. **Przeanalizuj obecne ładowanie** — otwórz DevTools → Network → filtruj po domenie. Zbierz wszystkie third-party hosty, które faktycznie są używane. Pomocna może być też [lista sposobów na sprawdzenie cookies i trackerów na stronie](/blog/jak-sprawdzic-cookies-i-trackery-na-stronie/), żeby nie zapomnieć o domenach ładowanych dopiero po akceptacji consent.
2. **Wdrożenie w trybie Report-Only** na co najmniej 7 dni. Produkcyjny ruch ujawni przypadki brzegowe, których nie widać na dev/staging (stare podstrony, szablony maili otwierane w przeglądarce, warianty A/B testów).
3. **Raporty skieruj do prawdziwego endpointu** — użyj [Report URI](https://report-uri.com/) lub własnego loggera. Posortuj naruszenia według częstotliwości.
4. **Zaostrzaj dyrektywa po dyrektywie.** Najpierw wymuszaj `img-src` (niskie ryzyko), potem `style-src`, `connect-src`, a na końcu `script-src` (największe ryzyko przestoju).
5. **Przełącz na enforce mode** z tą samą polityką. Równolegle zostaw nagłówek Report-Only do testowania kolejnej, ostrzejszej iteracji.
6. **Rewiduj co kwartał** — Google dokłada nowe domeny (np. `analytics.google.com/g/collect`, regionalne `region1/2/3.google-analytics.com`). Twoja polityka musi za tym nadążać.

## Sprawdź swoje CSP w czasie rzeczywistym z UPER SEO Auditor

Jeśli chcesz ciągły monitoring Content-Security-Policy bez kopiowania nagłówków do zewnętrznych walidatorów, zainstaluj naszą wtyczkę Chrome **[UPER SEO Auditor](https://chromewebstore.google.com/detail/uper-seo-auditor/khhpbeckpphaoiemjdijhbfpjnendage)**. Zakładka Security:

- **Rozbija Twoje CSP** na poszczególne dyrektywy i pokazuje każde źródło osobno — od razu widać brakujące domeny.
- **Wyłapuje naruszenia CSP na żywo** podczas przeglądania strony — każdy zablokowany zasób jest pogrupowany według dyrektywy, z **flagą `[Google]` przy blokadach dotyczących usług Google** (GTM, GA4, Maps, Fonts, reCAPTCHA).
- **Ostrzega, gdy CSP jest w trybie Report-Only** — nie wdrożysz przez pomyłkę polityki, która niczego nie egzekwuje.
- **Sprawdza 10 nagłówków bezpieczeństwa** poza CSP (HSTS, X-Frame-Options, Referrer-Policy, Permissions-Policy, COOP, COEP, CORP) z ważonym scorem 0-10.

Darmowa, działa lokalnie w przeglądarce — żadne dane nie opuszczają strony.

## Podsumowanie

**CSP dla usług Google** wymaga balansu między bezpieczeństwem a funkcjonalnością:

1. **GTM wymaga kompromisów** — `'unsafe-inline'` jest często konieczny, chyba że zaadoptujesz nonce + `'strict-dynamic'`
2. **Server-side GTM** znacząco upraszcza CSP i eliminuje większość zewnętrznych domen skryptowych
3. **Nonce + strict-dynamic** to aktualna dobra praktyka dla script-src
4. **Consent Mode v2** wymaga otwartego `connect-src` do Google *przed* wyrażeniem zgody
5. **Testuj w Report-Only** przez minimum tydzień przed włączeniem wymuszania
6. **Monitoruj naruszenia** stale — domeny Google z czasem się zmieniają

Dobrze skonfigurowana polityka CSP chroni użytkowników przed XSS, nie blokując funkcjonalności strony.

<FaqBlog
  questions={[
    {
      question: 'Dlaczego Google Tag Manager wymaga unsafe-inline?',
      answer: 'GTM wstrzykuje inline\'owe skrypty dla kontenera i tagów Custom HTML. Bez <code>unsafe-inline</code> (lub pasującego nonce) przeglądarka blokuje te wstrzyknięcia i GTM przestaje odpalać tagi. Nowoczesne rozwiązanie to nonce generowany per-request dodany do snippetu GTM oraz dyrektywa <code>strict-dynamic</code>, która pozwala GTM przenieść zaufanie na ładowane przez niego tagi bez wypisywania każdej domeny.'
    },
    {
      question: 'Czy można bezpiecznie używać unsafe-eval z GTM?',
      answer: '<code>unsafe-eval</code> jest potrzebny tylko, gdy Twój kontener GTM ma tagi Custom HTML lub Custom JavaScript wywołujące <code>eval()</code> lub <code>new Function()</code>. Większość tagów GA4 i Ads tego nie robi. Przejrzyj kontener w trybie Preview, usuń stare Custom HTML tam, gdzie to możliwe, a następnie wyrzuć <code>unsafe-eval</code> z polityki — znacząco osłabia on ochronę przed XSS.'
    },
    {
      question: 'Jak naprawić błąd "Refused to load googletagmanager.com"?',
      answer: 'Dodaj <code>https://www.googletagmanager.com</code> do <code>script-src</code>. Jeśli dodatkowo ładujesz GA4 przez gtag.js w GTM, dodaj <code>https://www.google-analytics.com</code> do <code>img-src</code> i <code>connect-src</code>, a także <code>https://*.google-analytics.com</code>, jeśli pojawiają się błędy dla endpointów regionalnych.'
    },
    {
      question: 'Czy Google Consent Mode v2 wymaga specjalnych zmian w CSP?',
      answer: 'Consent Mode v2 używa tych samych domen Google co GTM i GA4, więc jeśli tamte działają — Consent Mode też. Kluczowa różnica to fakt, że <code>connect-src</code> musi być otwarty do endpointów Google Analytics od pierwszego wejścia — Consent Mode wysyła pingi do Google w stanie "denied" jeszcze przed akceptacją cookies. Dodatkowo dodaj do whitelisty swojego dostawcę CMP (Cookiebot, Iubenda, OneTrust itp.).'
    },
    {
      question: 'Czy server-side GTM eliminuje potrzebę unsafe-inline?',
      answer: 'Tak, i to jedna z jego największych zalet. Z server-side tagging na Twojej stronie ładuje się tylko mały first-party loader (często jeden skrypt z Twojej subdomeny), a ciężka logika tagów działa w kontenerze server-side. <code>script-src</code> można zredukować do <code>self</code> plus subdomena tagująca, z nonce — bez <code>unsafe-inline</code>, bez zewnętrznych domen Google w przeglądarce.'
    },
    {
      question: 'Jak testować CSP bez ryzyka dla produkcji?',
      answer: 'Użyj nagłówka <code>Content-Security-Policy-Report-Only</code>. Przeglądarka przetwarza politykę i wysyła raporty naruszeń na <code>report-uri</code>, ale niczego nie blokuje. Uruchom tryb Report-Only przez co najmniej 7 dni na realnym ruchu, przejrzyj raporty, dociśnij politykę, a dopiero potem przełącz na wymuszający nagłówek <code>Content-Security-Policy</code>.'
    },
    {
      question: 'Jaka jest różnica między nonce a hash w CSP?',
      answer: '<strong>Nonce</strong> to losowa wartość generowana per-request i dołączana do każdego zaufanego inline\'owego skryptu; przeglądarka uruchamia tylko te skrypty, których nonce pasuje do wartości w nagłówku CSP. <strong>Hash</strong> to fingerprint SHA-256 zawartości skryptu — przydatny, gdy skrypt się nie zmienia, ale kruchy, bo każda edycja go łamie. Nonce stosuj dla dynamicznej zawartości (GTM, React SSR), hashe dla statycznych snippetów inline.'
    },
    {
      question: 'Dlaczego zapytania do region1.google-analytics.com są blokowane?',
      answer: 'GA4 wysyła hity kolekcjonera na regionalne endpointy (<code>region1</code>, <code>region2</code>, <code>region3</code>.google-analytics.com) zależnie od lokalizacji użytkownika. Jeśli dodałeś do whitelisty tylko <code>www.google-analytics.com</code>, ruch regionalny jest blokowany. Użyj wildcardu: <code>https://*.google-analytics.com</code> w <code>connect-src</code>.'
    }
  ]}
  heading="Najczęściej zadawane pytania o CSP dla usług Google"
  id="faq"
/>

## Źródła

1. **MDN — Content-Security-Policy**
[https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)

2. **Google — CSP for Google Tag Manager**
[https://developers.google.com/tag-platform/tag-manager/csp](https://developers.google.com/tag-platform/tag-manager/csp)

3. **Google — CSP Evaluator**
[https://csp-evaluator.withgoogle.com/](https://csp-evaluator.withgoogle.com/)

4. **web.dev — Content Security Policy**
[https://web.dev/articles/csp](https://web.dev/articles/csp)

5. **Google Maps Platform — CSP**
[https://developers.google.com/maps/documentation/javascript/content-security-policy](https://developers.google.com/maps/documentation/javascript/content-security-policy)
