Anteprima sicura di siti esterni — implementare proxy + sanitizzazione + iframe sandbox
- engineering
- security
- nextjs
- iframe
In sintesi
- Caricare un sito esterno in un iframe sulla propria origine comporta il rischio che il JS esterno interagisca con la sessione dell'origine stessa
- La contromisura è una difesa a più livelli: "proxy con protezione SSRF + rimozione del JS esterno + CSP restrittiva + iframe sandbox"
- Una sandbox troppo restrittiva blocca anche i propri script personalizzati: dimenticare
allow-scriptsè un'insidia che impedisce il funzionamento della funzionalità
Gli A/B test di HeatMapX includono una funzionalità che permette di "visualizzare in anteprima l'aspetto dopo la modifica (Variant B), applicata alla pagina di destinazione". Da un punto di vista tecnico, si tratta di "mostrare in sicurezza il sito esterno dell'utente all'interno di un iframe sul proprio dominio", un'operazione sorprendentemente delicata. Condividiamo qui il design adottato e le insidie incontrate nella pratica.
Perché un'implementazione ingenua è pericolosa
Se si recupera l'HTML del sito esterno così com'è e lo si serve dalla propria origine (ad esempio heatmapx.com), i tag <script> o gli attributi onclick= contenuti in quell'HTML verrebbero eseguiti con i privilegi della propria origine. Questo espone al rischio che vengano letti cookie o sessioni di login. È una situazione da evitare assolutamente.
Struttura della difesa a più livelli
Per questo motivo abbiamo sovrapposto i seguenti livelli.
1. Proxy con protezione SSRF
Verifichiamo l'URL di destinazione e rifiutiamo tutto ciò che non sia http/https. Blocchiamo inoltre localhost, gli IP privati e gli endpoint dei metadati cloud (ad esempio 169.254.169.254). I redirect non vengono seguiti automaticamente: con redirect: 'manual' li verifichiamo nuovamente uno alla volta, per evitare di essere indirizzati verso la rete interna.
2. Rimozione del JS esterno (sanitizzazione)
Dall'HTML recuperato rimuoviamo i tag <script>, i gestori inline on*= e lo schema javascript:. Non c'è alcuna necessità di eseguire il JS del sito del cliente in fase di anteprima (il fatto che una SPA non possa essere riprodotta perfettamente è un compromesso accettato e noto).
3. CSP restrittiva e base href
Subito dopo <head> inseriamo un <base href> per risolvere i percorsi relativi di immagini e CSS, mentre alla risposta applichiamo una CSP restrittiva che "non consente l'esecuzione di JS esterno". Immagini e CSS restano consentiti perché necessari alla visualizzazione.
4. iframe sandbox
Infine, isoliamo il lato di visualizzazione applicando l'attributo sandbox all'iframe.
L'insidia incontrata: una sandbox troppo restrittiva
Per l'anteprima iniettiamo nell'HTML recuperato un piccolo script personalizzato che "applica la modifica (changeSet)" ed eseguiamo quello script all'interno dell'iframe per cambiarne l'aspetto. Il problema era che la sandbox dell'iframe di anteprima aveva solo allow-same-origin, e mancava allow-scripts.
Il risultato era che anche lo script personalizzato non veniva eseguito, causando un malfunzionamento per cui veniva mostrata la pagina originale, senza che la modifica venisse applicata. L'iframe lato editor, usato per la modifica, funzionava correttamente con allow-scripts allow-same-origin: la causa era quindi una discrepanza nella configurazione.
La correzione è stata semplice: allineare anche il lato anteprima a allow-scripts allow-same-origin. Contestualmente, abbiamo aggiunto un test di regressione che verifica l'attributo sandbox dell'iframe.
sandbox="allow-same-origin" → sandbox="allow-scripts allow-same-origin"
Lezioni apprese
- L'incorporazione di contenuti esterni va pensata in termini di "difesa a più livelli": non affidarsi a una singola contromisura.
- Con
sandboxnon basta "applicarlo" per essere al sicuro: ciò che conta è concedere con precisione solo i permessi necessari. Se è troppo restrittivo, blocca anche le proprie funzionalità. - Quando esistono "due percorsi che eseguono la stessa elaborazione" (editor e anteprima), verificare sempre che gli attributi di sicurezza siano allineati. Correggerne uno soltanto rischia di rompere l'altro.
Conclusione
Un'anteprima sicura di siti esterni si ottiene con una difesa a più livelli: protezione SSRF, rimozione del JS esterno, CSP restrittiva e iframe sandbox. E i permessi della sandbox creano problemi sia se sono insufficienti sia se sono eccessivi. La dimenticanza di allow-scripts di cui abbiamo parlato ne è un esempio tipico.