Novità in Twig 4.0: una sandbox di prima classe (Blog di Symfony)
La sandbox fa parte di Twig dal 2009. Se i tuoi utenti scrivono newsletter, blocchi CMS o temi email, la sandbox è il componente che tiene la loro creatività lontano dalle parti interne della tua applicazione. Per diciassette anni, ha svolto quel ruolo come estensione aggiunta all'ambiente della tua applicazione. Twig 4.0 la promuove a cittadino di prima classe: una classe Sandbox dedicata che possiede un ambiente costruito per template non attendibili, e per nient'altro. Lascia che ti mostri come funziona.
La sandbox storica condivide tutto con la tua applicazione. Per renderizzare un template non attendibile, si attiva la modalità sandbox nell'ambiente principale e ci si ricorda di disattivarla in seguito:
La documentazione raccomandava un ambiente dedicato, e gli sviluppatori attenti ne creavano uno a mano. Ma l'API non lo richiedeva mai. Ho scritto quel progetto, e per molto tempo l'ho ritenuto sufficiente: un ambiente, un interruttore.
Condividere, però, è esattamente ciò che non vuoi a un confine di sicurezza. Un template non attendibile poteva caricare qualsiasi template noto al loader dell'applicazione quando il caricamento dei template era consentito dalla policy. Vedeva ogni variabile globale registrata, inclusa la tua variabile app, ed ereditava ogni estensione, filtro, funzione e test usati dalla tua applicazione. La security policy doveva compensare un ambiente che non era mai stato progettato per codice non attendibile.
Twig 4.0 offre ai template in sandbox un ambiente dedicato, senza stato condiviso da attivare e senza configurazione dell'applicazione ereditata per sbaglio.
Il nuovo modello si riassume in una frase: costruisci un ambiente per template non attendibili e una Sandbox ne assume la proprietà:
L'ambiente deve essere nuovo e dedicato alla sandbox. Passare un ambiente che ha già renderizzato un template o che ha già una SandboxExtension genera una LogicException invece di creare un setup parzialmente isolato. Non passare mai l'ambiente della tua applicazione: la sandbox ne assume la proprietà e renderizza tutti i suoi template in modalità sandbox.
Sandbox implementa SandboxInterface. Usa il type-hint dell'interfaccia quando inietti una sandbox in un servizio dell'applicazione.
Ogni argomento risponde a una domanda. Il loader dell'ambiente definisce quali template esistono. Le sue estensioni, i filtri, le funzioni, i test e le variabili globali integrati e registrati definiscono le capacità disponibili. La policy decide quali di queste capacità possono essere eseguite e a quali metodi e proprietà si può accedere sugli oggetti del contesto.
Non c'è modalità da attivare né stato da ripristinare. Tutto ciò che viene renderizzato tramite una Sandbox è in sandbox: render(), display() e stream(), le loro controparti per i blocchi renderBlock(), displayBlock() e streamBlock(), e i template restituiti da createTemplate(). E poiché l'ambiente della tua applicazione non è coinvolto, un rendering attendibile che avviene nel mezzo di uno in sandbox non viene messo in sandbox. L'isolamento funziona in entrambe le direzioni.
La SecurityPolicy di Twig 4.0 non ha più le eccezioni storiche che consentivano implicitamente alcuni tag, funzioni e test. Qualsiasi cosa che non sia in una allow-list viene negata, tranne i built-in che Twig contrassegna come sempre sicuri in una sandbox. La chiamata setStrict(true) adotta queste regole in Twig 3.29; su Twig 4.0 è un no-op innocuo, quindi la stessa configurazione funziona su entrambe le versioni.
Cosa succede quando un autore di template va oltre la policy o il loader dedicato? Twig segnala la capacità o il template esatto coinvolto:
Filter "json_encode" is not allowed in "newsletter.twig" at line 1.Calling "delete" method on a "Customer" object is not allowed in "profile.twig" at line 1.Template "admin/config.html.twig" is not defined in "page.twig" at line 1.
L'ultimo errore viene dal loader, non dalla policy. I template non sono un'altra allow-list: include, extends e i loro simili possono risolvere i nomi solo tramite il loader dell'ambiente sandbox.
Un confine merita ancora di essere chiarito. La sandbox limita ciò che il sorgente del template può esprimere; il codice PHP invocato da un filtro, una funzione o un'estensione consentita viene comunque eseguito con tutte le capacità di PHP. Registra solo callable che siano sicure con argomenti scelti dall'attaccante e imponi limiti di CPU e memoria al di fuori di Twig quando l'esaurimento delle risorse è una preoccupazione.
Lo scenario CMS classico è una pagina attendibile che incorpora blocchi scritti dagli utenti. Per farlo, registra la SandboxBridgeExtension e inietta la sandbox in modo lazy nel suo runtime:
Il tuo template attendibile può quindi chiamare render_sandboxed():
La mappatura del contesto è il contesto completo passato al template in sandbox; le variabili del template attendibile non vengono copiate implicitamente. Il terzo argomento dichiara la strategia di escaping per cui il risultato è sicuro. A differenza di |raw, questo mantiene il risultato sicuro solo in HTML e consente a Twig di applicare l'escaping quando viene usato in un altro contesto, come JavaScript.
La strategia deve essere una stringa letterale non vuota diversa da all. Non sanifica il frammento: dichiarare html significa che l'HTML scritto dall'autore del template non attendibile può arrivare nella risposta, e questa dovrebbe essere una decisione esplicita dell'applicazione.
Twig 3.29 depreca l'argomento sandboxed di include() e i metodi legacy di SandboxExtension, completando il percorso iniziato con le precedenti deprecazioni 3.x. I loro sostituti, la classe Sandbox e la funzione render_sandboxed(), funzionano su 3.29, quindi una configurazione che non usa più le API legacy è pronta per Twig 4.0.
Altri articoli recenti
Laravel AI 1.1 e 1.2: Agent Skills, Cohere e structured output più solidi
Le release 1.1.0 e 1.2.0 di laravel/ai portano gli Agent Skills, l'approvazione obbligatoria per i tool built-in e nuovi provider come Cohere e Laya self-hosted. Sul fronte qualità arrivano i fix allo structured output per Bedrock e il supporto alle provider options. Aggiornati anche i modelli di default, con Claude 4.7+ che ignora i sampling params.
Laravel 13.35.0: scheduler più controllabile, code più flessibili e response Markdown
Laravel 13.35.0 porta Schedule::alwaysOnOneServer(), il supporto a schedule:interrupt per i comandi di lunga durata, --memory in percentuale per queue:work e il nuovo metodo markdown() sulla response factory. Tante piccole migliorie anche a test, view compilate in parallelo e dischi local.
BashBox: un interprete Bash in sandbox per agenti AI in PHP
BashBox è un interprete bash scritto in puro PHP che permette di eseguire gli script generati dagli agenti AI senza mai ricorrere a proc_open, exec o shell_exec. Ogni comando è una classe PHP che lavora su un filesystem virtuale, con limiti di esecuzione, quote disco e accesso di rete configurabili. Ideale per chi sviluppa agenti con il Laravel AI SDK o altre librerie simili.