MAISON CODE .
/ Security · CSP · XSS · Headers · Compliance

Content Security Policy (CSP): il sistema immunitario del web

Prevenire gli attacchi XSS e Magecart. Una guida definitiva all'implementazione di Strict CSP con Nonces, modalità Report-Only e "strict-dynamic" in Remix/Hydrogen.

AB
Alex B.
Content Security Policy (CSP): il sistema immunitario del web

Nel 2018, British Airways ha subito una catastrofica violazione dei dati. Gli hacker hanno rubato i dettagli delle carte di credito di 380.000 clienti. Non sono entrati nel database. Non hanno indovinato la password dell’amministratore. Hanno inserito 22 righe di JavaScript nella pagina di pagamento tramite una libreria di terze parti compromessa. Questo script legge silenziosamente gli input del modulo e li invia a “baways.com” (un dominio falso).

Questo è un Attacco alla catena di rifornimento (nello specifico Formjacking o Magecart). La parte spaventosa? Il tuo firewall (WAF) non può fermarlo. La richiesta proviene dal browser dell’utente, non dal tuo server.

L’unica difesa contro questo è la Content Security Policy (CSP). CSP è un’intestazione HTTP che dice al browser: “Questi sono i domini attendibili. Blocca tutto il resto.”

Noi di Maison Code Paris consideriamo il CSP obbligatorio per qualsiasi sito che esegue transazioni. Operare senza di essa è come lasciare la porta del caveau aperta perché “la serratura è difficile da usare”.

Perché Maison Code ne parla

In Maison Code Paris, agiamo come la coscienza architettonica dei nostri clienti. Spesso ereditiamo stack “moderni” costruiti senza una comprensione fondamentale della scala.

Discutiamo di questo argomento perché rappresenta un punto di svolta critico nella maturità ingegneristica. Implementarlo correttamente differenzia un MVP fragile da una piattaforma resiliente di livello aziendale.

Perché il codice Maison applica un CSP rigoroso

La sicurezza non è un componente aggiuntivo; è la nostra linea di base. Per il commercio al dettaglio specializzato di alto valore, il rischio di Magecart (Digital Skimming) è esistenziale. Recentemente abbiamo controllato un potenziale cliente e abbiamo trovato un plugin jQuery dannoso che raccoglieva input di carte di credito. Era lì da 6 mesi. Un CSP rigoroso lo avrebbe bloccato immediatamente. Implementiamo **CSP non basati su **** su ogni vetrina Headless che spediamo, garantendo che solo il codice di cui ci fidiamo esplicitamente possa essere eseguito nel browser del cliente.

Il meccanismo: whitelist

Per impostazione predefinita, i browser Web esistenti sono promiscui. Se l’HTML dice <script src="https://evil.com/hack.js">, il browser lo carica. CSP modifica questa impostazione predefinita in “Nega tutto”.

Politica di sicurezza dei contenuti: default-src 'self'; script-src 'self' https://analytics.google.com;

Con questa intestazione, se un utente malintenzionato inserisce <script src="https://evil.com/hack.js">, la console del browser urla in rosso: Rifiutato di caricare lo script perché viola la seguente direttiva sulla politica di sicurezza dei contenuti. Lo script non viene mai eseguito.

La strategia: CSP non basato su nonce (CSP rigoroso)

I domini autorizzati (https://google.com) sono fragili. Google ospita milioni di script (Drive, Maps, Contenuti utente). Se un utente malintenzionato riesce a caricare un file su Google Drive, può ignorare la tua lista bianca.

Il Gold Standard è **CSP non basato su **. Un Nonce (Numero utilizzato UNA VOLTA) è un token crittografico casuale generato dal server per ogni singola richiesta.

  1. Generazione del server: const nonce = crypto.randomBytes(16).toString('base64'); // "r4nd0m"
  2. Intestazione: script-src 'nonce-r4nd0m'
  3. Iniezione HTML: <script nonce="r4nd0m" src="/app.js"></script>

Se un utente malintenzionato inserisce <script>alert(1)</script>, non riconosce il nonce. Il browser lo blocca.

Implementazione in idrogeno (Remix)

In un’app Server-Side Rendered (SSR) come Hydrogen, generiamo il nonce in “entry.server.tsx”.

“tsx // app/entry.server.tsx import {creaContentSecurityPolicy} da ‘@shopify/idrogen’;

esporta la funzione asincrona predefinita handleRequest (richiesta, rispostaStatusCode, rispostaHeaders, remixContext) { // L’helper di Hydrogen genera il nonce e l’intestazione const { nonce, intestazione, NonceProvider } = createContentSecurityPolicy({ // Direttive standard defaultSrc: [“‘self’”], imgSrc: [“‘self’”, ‘cdn.shopify.com’, ‘data:’, ‘https://www.google-analytics.com’], styleSrc: [“‘self’”, “‘unsafe-inline’”], // Valido per componenti con stile connectSrc: [“‘self’”, ‘https://monorail-edge.shopifysvc.com’, ‘https://vitals.vercel-insights.com’],

// La parte critica
scriptSrc: [
  "'sé'",
  // 'strict-dynamic' dice ai browser moderni: "Fidati di qualsiasi script caricato da uno script attendibile"
  // Ciò consente a GTM di caricare Facebook Pixel senza che Facebook venga esplicitamente inserito nella whitelist.
  "'rigoroso-dinamico'", 
  // Fallback per i browser più vecchi
  'https://cdn.shopify.com',
  "https://www.googletagmanager.com" 
],

});

rispostaHeaders.set(‘Content-Security-Policy’, intestazione);

ritorno ( // NonceProvider passa il nonce al componente ); }


## La Direttiva "Dinamica Rigorosa".

I siti moderni utilizzano **Google Tag Manager (GTM)**.
GTM carica il pixel di Facebook. Facebook Pixel carica altri script di monitoraggio.
Non è possibile prevedere l'intero albero delle dipendenze.
Ciò ha portato gli sviluppatori ad abilitare "unsafe-eval" e "unsafe-inline", che vanificano lo scopo del CSP.

**`strict-dynamic`** risolve questo problema.
Dice: "Se uno script è attendibile (ha un nonce valido), consentigli di caricare altri script in modo dinamico".
Poiché ci fidiamo di GTM (non facendolo), ci fidiamo di ciò che GTM carica.
*Avvertenza: questo ripone molta fiducia in GTM. Assicurati che il tuo contenitore GTM abbia controlli di accesso rigorosi.*

## Direttive identificative

Una politica solida copre più dei semplici script.

1. **`base-uri 'none'`**: impedisce il dirottamento del tag `<base>` (reindirizzamento dei collegamenti relativi a siti dannosi).
2. **`object-src 'none'`**: blocca Flash, applet Java e `<embed>`.
3. **`frame-antences 'none'`**: Previene il clickjacking. Il tuo sito non può essere inserito in un Iframe.
4. **`form-action 'self'`**: garantisce che i moduli possano essere inviati solo alla tua API. Impedisce agli aggressori di modificare un'azione del modulo sul proprio server.
5. **`connect-src`**: limita `fetch()` / `XHR`. Anche se un utente malintenzionato esegue JS, non può inviare i dati a "evil.com".

## Distribuzione sicura: la modalità solo report

Non è possibile "Attivare" CSP venerdì pomeriggio. Romperai il sito.
Bloccherai il Chat Widget. Bloccherai l'app Recensioni.
Inizi in **Modalità Solo report**.

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

Il browser eseguirà tutto, ma invierà un rapporto di violazione JSON al tuo backend ogni volta che *avrebbe* bloccato qualcosa.

### L'endpoint del servizio di raccolta
È necessario un servizio per acquisire questi report.
Usare **Sentry** o **Datadog** è la soluzione migliore; visualizzano le violazioni.

```json
{
  "rapporto csp": {
    "document-uri": "https://maisoncode.paris/checkout",
    "riferente": "",
    "direttiva-violata": "script-src",
    "direttiva-efficace": "script-src",
    "original-policy": "default-src 'self'; script-src 'nonce-xyz'",
    "blocked-uri": "https://malicious-analytics.com/tracker.js",
    "codice di stato": 200
  }
}

Flusso di lavoro:

  1. Distribuire “Solo report”.
  2. Attendi 1 settimana.
  3. Analizzare i log. “Ah, abbiamo dimenticato di inserire nella whitelist il tag Pinterest.”
  4. Politica di aggiornamento.
  5. Quando i log sono silenziosi (solo attacchi effettivi), passa a “Content-Security-Policy” (Enforce).

Codice di refactoring per CSP

CSP ti costringe a scrivere codice migliore. Blocca i gestori di eventi in linea.

Errore (bloccato): <button onclick="trackClick()">Acquista</button>

Buono (consentito): <button id="buyBtn">Acquista</button> <script nonce="...">document.getElementById('buyBtn').addEventListener('click', trackClick);</script>

Separa il comportamento dal markup.

10. Tipi affidabili (il futuro della prevenzione XSS)

CSP blocca la fonte dello script. Tipi attendibili blocca il sink (innerHTML). Costringe gli sviluppatori a disinfettare le stringhe prima di inserirle. div.innerHTML = string -> Bloccato. div.innerHTML = TrustedHTML.create(string) -> Consentito. Ciò elimina le vulnerabilità DOM XSS a livello del motore del browser. È severo (“Modalità Difficile”), ma per la sicurezza di livello bancario è la fine del gioco.

11. Edge CSP (lavoratori Cloudflare)

Generare CSP all’origine (Node.js) è utile. Iniettarlo sull’Edge è meglio. Utilizziamo Cloudflare Workers per inserire intestazioni di sicurezza. Ciò protegge le risorse statiche (immagini, file HTML semplici) che potrebbero non passare attraverso la logica dell’applicazione Node.js. Consente inoltre il “Blocco di emergenza”. Se una libreria viene compromessa, possiamo aggiornare il CSP sull’Edge in 300 ms a livello globale.

13. CSP in un mondo micro-frontend

Cosa succede se carichi un widget dalla squadra B? Non è possibile condividere il Nonce (viene generato sul server). CSP basato su hash. Invece del noncing, calcoli l’hash SHA-256 del contenuto dello script. “script-src ‘sha256-K7g…’”. Il browser esegue l’hashing dello script in linea. Se corrisponde, viene eseguito.

  • Pro: Statico. Può essere memorizzato nella cache.
  • Contro: Se cambi un carattere (anche uno spazio), l’hash si rompe. Lo utilizziamo per script stabili di fornitori di terze parti che raramente cambiano versione.

14. La parola chiave “Unsafe-Hash”.

A volte devi utilizzare gestori di eventi in linea (librerie legacy). navigate('foo') all’interno di un onclick. Il CSP standard lo blocca. 'unsafe-hashes' ti consente di inserire nella whitelist stringhe di gestori di eventi specifici. script-src 'unsafe-hashes' 'sha256-...' (dove hash è “navigate(‘foo’)”). Ciò ti consente di bloccare il codice legacy senza riscrivere l’intero modello di eventi DOM.

15. Conclusione

La Content Security Policy è la cintura di sicurezza del web. Non impedisce lo schianto (iniezione), ma impedisce di volare attraverso il parabrezza (esfiltrazione di dati). È noioso da configurare. Richiede una manutenzione costante man mano che si aggiungono nuovi strumenti di marketing. Ma per un marchio di lusso che ha a che fare con individui con un patrimonio netto elevato, questa è la base della fiducia.


Il tuo sito è completamente aperto?

Se non invii un’intestazione CSP, sei vulnerabile a Magecart.

Verifica di sicurezza. Assumi i nostri architetti.