Angular
La Checklist
Checklist da qui.
Cos'è Angular
Angular è un framework front-end potente e open-source mantenuto da Google. Utilizza TypeScript per migliorare la leggibilità e il debug del codice. Con meccanismi di sicurezza robusti, Angular previene vulnerabilità comuni lato client come XSS e reindirizzamenti aperti. Può essere utilizzato anche lato server, rendendo importanti le considerazioni sulla sicurezza da entrambi i lati.
Architettura del framework
Per comprendere meglio i concetti fondamentali di Angular, esaminiamo la struttura di un progetto Angular comune:
Secondo la documentazione, ogni applicazione Angular ha almeno un componente, il componente radice (AppComponent
) che collega una gerarchia di componenti al DOM. Ogni componente definisce una classe che contiene dati e logica dell'applicazione ed è associato a un template HTML che definisce una vista da visualizzare in un ambiente target. Il decoratore @Component()
identifica la classe immediatamente sotto di esso come un componente e fornisce il template e i metadati specifici del componente. L'AppComponent
è definito nel file app.component.ts
.
Gli NgModule
di Angular dichiarano un contesto di compilazione per un insieme di componenti dedicato a un dominio dell'applicazione, a un flusso di lavoro o a un insieme di funzionalità strettamente correlate. Ogni applicazione Angular ha un modulo radice, convenzionalmente chiamato AppModule
, che fornisce il meccanismo di bootstrap per avviare l'applicazione. Un'applicazione contiene tipicamente molti moduli funzionali. L'AppModule
è definito nel file app.module.ts
.
L'NgModule
Router
di Angular fornisce un servizio che consente di definire un percorso di navigazione tra i diversi stati dell'applicazione e le gerarchie di visualizzazione nell'applicazione. Il RouterModule
è definito nel file app-routing.module.ts
.
Per i dati o la logica che non sono associati a una vista specifica e che si desidera condividere tra i componenti, si crea una classe di servizio. La definizione di una classe di servizio è immediatamente preceduta dal decoratore @Injectable()
. Il decoratore fornisce i metadati che consentono l'iniezione di altre dipendenze nel tuo classe. L'iniezione di dipendenze (DI) consente di mantenere le classi dei componenti snelle ed efficienti. Non recuperano dati dal server, convalidano l'input dell'utente o registrano direttamente sulla console; delegano tali compiti ai servizi.
Configurazione del sourcemap
Il framework Angular traduce i file TypeScript in codice JavaScript seguendo le opzioni del file tsconfig.json
e quindi costruisce un progetto con la configurazione di angular.json
. Osservando il file angular.json
, abbiamo notato un'opzione per abilitare o disabilitare un sourcemap. Secondo la documentazione di Angular, la configurazione predefinita ha un file sourcemap abilitato per gli script e non è nascosto per impostazione predefinita:
Generalmente, i file sourcemap vengono utilizzati per scopi di debug in quanto mappano i file generati ai loro file originali. Pertanto, non è consigliabile utilizzarli in un ambiente di produzione. Se i sourcemap sono abilitati, migliorano la leggibilità e aiutano nell'analisi dei file riproducendo lo stato originale del progetto Angular. Tuttavia, se sono disabilitati, un revisore può comunque analizzare manualmente un file JavaScript compilato cercando modelli anti-sicurezza.
Inoltre, un file JavaScript compilato con un progetto Angular può essere trovato negli strumenti di sviluppo del browser → Sorgenti (o Debugger e Sorgenti) → [id].main.js. A seconda delle opzioni abilitate, questo file può contenere la seguente riga alla fine //# sourceMappingURL=[id].main.js.map
o potrebbe non contenerla, se l'opzione hidden è impostata su true. Tuttavia, se il sourcemap è disabilitato per gli script, il testing diventa più complesso e non possiamo ottenere il file. Inoltre, il sourcemap può essere abilitato durante la compilazione del progetto come ng build --source-map
.
Binding dei dati
Il binding si riferisce al processo di comunicazione tra un componente e la sua vista corrispondente. Viene utilizzato per trasferire dati da e verso il framework Angular. I dati possono essere passati attraverso vari mezzi, come eventi, interpolazione, proprietà o tramite il meccanismo di binding bidirezionale. Inoltre, i dati possono essere condivisi tra componenti correlati (relazione padre-figlio) e tra due componenti non correlati utilizzando la funzionalità di Service.
Possiamo classificare il binding in base al flusso dei dati:
Sorgente dei dati verso il target della vista (include interpolazione, proprietà, attributi, classi e stili); può essere applicato utilizzando
[]
o{{}}
nel template;Target della vista verso la sorgente dei dati (include eventi); può essere applicato utilizzando
()
nel template;Bidirezionale; può essere applicato utilizzando
[()]
nel template.
Il binding può essere applicato alle proprietà, agli eventi e agli attributi, nonché a qualsiasi membro pubblico di una direttiva di origine:
TIPO | TARGET | ESEMPI |
---|---|---|
Proprietà | Proprietà dell'elemento, proprietà del componente, proprietà della direttiva | <img [alt]="hero.name" [src]="heroImageUrl"> |
Evento | Evento dell'elemento, evento del componente, evento della direttiva | <button type="button" (click)="onSave()">Save |
Bidirezionale | Evento e proprietà | <input [(ngModel)]="name"> |
Attributo | Attributo (l'eccezione) | <button type="button" [attr.aria-label]="help">help |
Classe | Proprietà della classe | <div [class.special]="isSpecial">Special |
Stile | Proprietà dello stile | <button type="button" [style.color]="isSpecial ? 'red' : 'green'"> |
Modello di sicurezza di Angular
Il design di Angular include la codifica o la sanificazione di tutti i dati per impostazione predefinita, rendendo sempre più difficile scoprire ed sfruttare vulnerabilità XSS nei progetti Angular. Ci sono due scenari distinti per la gestione dei dati:
Interpolazione o
{{user_input}}
- esegue la codifica sensibile al contesto e interpreta l'input dell'utente come testo;
Risultato: <script>alert(1)</script><h1>test</h1>
2. Binding alle proprietà, agli attributi, alle classi e agli stili o [attributo]="user_input"
- esegue la sanificazione in base al contesto di sicurezza fornito.
Risultato: <div><h1>test</h1></div>
Ci sono 6 tipi di SecurityContext
:
None
;HTML
viene utilizzato quando si interpreta il valore come HTML;STYLE
viene utilizzato quando si esegue il binding del CSS nella proprietàstyle
;URL
viene utilizzato per le proprietà URL, come<a href>
;SCRIPT
viene utilizzato per il codice JavaScript;RESOURCE_URL
come URL che viene caricato ed eseguito come codice, ad esempio in<script src>
.
Vulnerabilità
Bypass dei metodi di fiducia della sicurezza
Angular introduce una serie di metodi per eludere il suo processo di sanificazione predefinito e per indicare che un valore può essere utilizzato in modo sicuro in un contesto specifico, come nei seguenti cinque esempi:
bypassSecurityTrustUrl
viene utilizzato per indicare che il valore fornito è un URL di stile sicuro:
bypassSecurityTrustResourceUrl
viene utilizzato per indicare che il valore fornito è un URL di risorsa sicuro:
bypassSecurityTrustHtml
viene utilizzato per indicare che il valore fornito è HTML sicuro. Nota che l'inserimento di elementiscript
nell'albero DOM in questo modo non li fa eseguire il codice JavaScript incluso, a causa del modo in cui questi elementi vengono aggiunti all'albero DOM.
bypassSecurityTrustScript
viene utilizzato per indicare che il valore fornito è JavaScript sicuro. Tuttavia, abbiamo riscontrato che il suo comportamento è imprevedibile, poiché non siamo riusciti ad eseguire il codice JS nei template utilizzando questo metodo.
bypassSecurityTrustStyle
viene utilizzato per indicare che il valore fornito è CSS sicuro. L'esempio seguente illustra l'iniezione di CSS:
Angular fornisce un metodo sanitize
per sanificare i dati prima di visualizzarli nelle viste. Questo metodo utilizza il contesto di sicurezza fornito e pulisce l'input di conseguenza. È tuttavia fondamentale utilizzare il contesto di sicurezza corretto per i dati e il contesto specifici. Ad esempio, l'applicazione di un sanificatore con SecurityContext.URL
su contenuti HTML non fornisce protezione contro valori HTML pericolosi. In tali scenari, un uso improprio del contesto di sicurezza potrebbe portare a vulnerabilità XSS.
Iniezione HTML
Questa vulnerabilità si verifica quando l'input dell'utente è legato a una delle tre proprietà: innerHTML
, outerHTML
o iframe
srcdoc
. Mentre il legame a questi attributi interpreta l'HTML così com'è, l'input viene sanificato utilizzando SecurityContext.HTML
. Pertanto, è possibile l'iniezione di HTML, ma non il cross-site scripting (XSS).
Esempio di utilizzo di innerHTML
:
Il risultato è <div><h1>test</h1></div>
.
Iniezione di template
Rendering lato client (CSR)
Angular utilizza i template per costruire pagine dinamicamente. L'approccio prevede l'uso di espressioni di template racchiuse tra doppie parentesi graffe ({{}}
) che Angular valuta. In questo modo, il framework offre funzionalità aggiuntive. Ad esempio, un template come {{1+1}}
visualizzerà il risultato 2.
Di solito, Angular esegue l'escape dell'input utente che potrebbe essere confuso con espressioni di template (ad esempio, caratteri come `< > ' " ``). Ciò significa che sono necessari passaggi aggiuntivi per aggirare questa restrizione, come l'utilizzo di funzioni che generano oggetti stringa JavaScript per evitare l'uso di caratteri nella lista nera. Tuttavia, per ottenere ciò, è necessario considerare il contesto di Angular, le sue proprietà e le variabili. Pertanto, un attacco di iniezione di template potrebbe apparire come segue:
Come mostrato sopra: constructor
si riferisce allo scope della proprietà constructor
dell'oggetto, consentendoci di invocare il costruttore di String e eseguire un codice arbitrario.
Rendering lato server (SSR)
A differenza di CSR, che avviene nel DOM del browser, Angular Universal è responsabile del SSR dei file di template. Questi file vengono quindi consegnati all'utente. Nonostante questa distinzione, Angular Universal applica gli stessi meccanismi di sanitizzazione utilizzati in CSR per migliorare la sicurezza del SSR. Una vulnerabilità di injection di template in SSR può essere individuata allo stesso modo di CSR, perché il linguaggio di template utilizzato è lo stesso.
Naturalmente, esiste anche la possibilità di introdurre nuove vulnerabilità di injection di template quando si utilizzano motori di template di terze parti come Pug e Handlebars.
XSS
Interfacce DOM
Come precedentemente indicato, possiamo accedere direttamente al DOM utilizzando l'interfaccia Document. Se l'input dell'utente non viene convalidato in precedenza, può portare a vulnerabilità di cross-site scripting (XSS).
Abbiamo utilizzato i metodi document.write()
e document.createElement()
negli esempi seguenti:
Classi Angular
Ci sono alcune classi che possono essere utilizzate per lavorare con gli elementi DOM in Angular: ElementRef
, Renderer2
, Location
e Document
. Una descrizione dettagliata delle ultime due classi è fornita nella sezione Open redirects. La differenza principale tra le prime due è che l'API Renderer2
fornisce uno strato di astrazione tra l'elemento DOM e il codice del componente, mentre ElementRef
contiene solo un riferimento all'elemento. Pertanto, secondo la documentazione di Angular, l'API ElementRef
dovrebbe essere utilizzata solo come ultima risorsa quando è necessario un accesso diretto al DOM.
ElementRef
contiene la proprietànativeElement
, che può essere utilizzata per manipolare gli elementi DOM. Tuttavia, un uso improprio dinativeElement
può causare una vulnerabilità di injection XSS, come mostrato di seguito:
Nonostante il fatto che
Renderer2
fornisca un'API che può essere utilizzata in modo sicuro anche quando non è supportato un accesso diretto agli elementi nativi, presenta comunque alcune vulnerabilità di sicurezza. ConRenderer2
, è possibile impostare attributi su un elemento HTML utilizzando il metodosetAttribute()
, che non ha meccanismi di prevenzione XSS.
Per impostare la proprietà di un elemento DOM, è possibile utilizzare il metodo
Renderer2.setProperty()
e innescare un attacco XSS:
Durante la nostra ricerca, abbiamo esaminato anche il comportamento di altri metodi di Renderer2
, come setStyle()
, createComment()
e setValue()
, in relazione a XSS e iniezioni CSS. Tuttavia, non siamo riusciti a trovare vettori di attacco validi per questi metodi a causa delle loro limitazioni funzionali.
jQuery
jQuery è una libreria JavaScript veloce, leggera e ricca di funzionalità che può essere utilizzata nel progetto Angular per aiutare nella manipolazione degli oggetti HTML DOM. Tuttavia, come è noto, i metodi di questa libreria possono essere sfruttati per ottenere una vulnerabilità XSS. Per discutere come alcuni metodi vulnerabili di jQuery possono essere sfruttati nei progetti Angular, abbiamo aggiunto questa sottosezione.
Il metodo
html()
ottiene il contenuto HTML del primo elemento nell'insieme di elementi corrispondenti o imposta il contenuto HTML di ogni elemento corrispondente. Tuttavia, per design, qualsiasi costruttore o metodo di jQuery che accetta una stringa HTML può potenzialmente eseguire del codice. Ciò può avvenire tramite l'iniezione di tag<script>
o l'uso di attributi HTML che eseguono codice, come mostrato nell'esempio.
Il metodo
jQuery.parseHTML()
utilizza metodi nativi per convertire la stringa in un insieme di nodi DOM, che possono quindi essere inseriti nel documento.
Come accennato in precedenza, la maggior parte delle API di jQuery che accettano stringhe HTML eseguiranno script inclusi nell'HTML. Il metodo jQuery.parseHTML()
non esegue script nell'HTML analizzato a meno che keepScripts
non sia esplicitamente impostato su true
. Tuttavia, è comunque possibile eseguire script in modo indiretto nella maggior parte degli ambienti; ad esempio, tramite l'attributo <img onerror>
.
Open redirects
Interfacce DOM
Secondo la documentazione del W3C, gli oggetti window.location
e document.location
sono trattati come alias nei browser moderni. Ecco perché hanno un'implementazione simile di alcuni metodi e proprietà, che potrebbero causare un reindirizzamento aperto e attacchi DOM XSS con lo schema javascript://
, come indicato di seguito.
window.location.href
(edocument.location.href
)
Il modo canonico per ottenere l'oggetto di posizione DOM corrente è utilizzare window.location
. Può anche essere utilizzato per reindirizzare il browser a una nuova pagina. Di conseguenza, avere il controllo su questo oggetto ci consente di sfruttare una vulnerabilità di reindirizzamento aperto.
Il processo di sfruttamento è identico per gli scenari seguenti.
window.location.assign()
(edocument.location.assign()
)
Questo metodo fa sì che la finestra carichi e visualizzi il documento all'URL specificato. Se abbiamo il controllo su questo metodo, potrebbe essere un punto di ingresso per un attacco di reindirizzamento aperto.
window.location.replace()
(edocument.location.replace()
)
Questo metodo sostituisce la risorsa corrente con quella fornita dall'URL specificato.
La differenza rispetto al metodo assign()
è che dopo aver utilizzato window.location.replace()
, la pagina corrente non verrà salvata nella cronologia della sessione. Tuttavia, è comunque possibile sfruttare una vulnerabilità di reindirizzamento aperto quando abbiamo il controllo su questo metodo.
window.open()
Il metodo window.open()
prende un URL e carica la risorsa che identifica in una nuova o esistente scheda o finestra. Avere il controllo su questo metodo potrebbe anche essere un'opportunità per innescare una vulnerabilità XSS o di reindirizzamento aperto.
Classi di Angular
Secondo la documentazione di Angular, la classe
Document
di Angular è la stessa del documento DOM, il che significa che è possibile utilizzare vettori comuni per il documento DOM per sfruttare le vulnerabilità lato client in Angular. Le proprietà e i metodi diDocument.location
potrebbero essere punti di ingresso per attacchi di reindirizzamento aperto di successo, come mostrato nell'esempio:
Durante la fase di ricerca, abbiamo anche esaminato la classe
Location
di Angular per le vulnerabilità di reindirizzamento aperto, ma non sono stati trovati vettori validi.Location
è un servizio di Angular che le applicazioni possono utilizzare per interagire con l'URL corrente del browser. Questo servizio ha diversi metodi per manipolare l'URL fornito -go()
,replaceState()
, eprepareExternalUrl()
. Tuttavia, non possiamo usarli per il reindirizzamento verso un dominio esterno. Ad esempio:
Risultato: http://localhost:4200/http://google.com/about
La classe
Router
di Angular viene utilizzata principalmente per la navigazione all'interno dello stesso dominio e non introduce vulnerabilità aggiuntive all'applicazione:
Risultato: http://localhost:4200/https:
I seguenti metodi navigano anche all'interno del dominio:
Riferimenti
Last updated