Angular
La Checklist
Checklist à partir d'ici.
Qu'est-ce que Angular
Angular est un framework puissant et open-source maintenu par Google. Il utilise TypeScript pour améliorer la lisibilité du code et le débogage. Avec des mécanismes de sécurité solides, Angular prévient les vulnérabilités côté client courantes telles que les XSS et les redirections ouvertes. Il peut également être utilisé côté serveur, ce qui rend les considérations de sécurité importantes des deux côtés.
Architecture du framework
Pour mieux comprendre les bases d'Angular, passons en revue ses concepts essentiels.
Un projet Angular commun ressemble généralement à :
Selon la documentation, chaque application Angular a au moins un composant, le composant racine (AppComponent
) qui connecte une hiérarchie de composants avec le DOM. Chaque composant définit une classe qui contient les données et la logique de l'application, et est associé à un modèle HTML qui définit une vue à afficher dans un environnement cible. Le décorateur @Component()
identifie la classe immédiatement en dessous comme un composant, et fournit le modèle et les métadonnées spécifiques au composant. L'AppComponent
est défini dans le fichier app.component.ts
.
Les NgModules Angular déclarent un contexte de compilation pour un ensemble de composants dédié à un domaine d'application, un flux de travail, ou un ensemble de capacités étroitement liées. Chaque application Angular a un module racine, conventionnellement nommé AppModule
, qui fournit le mécanisme de démarrage qui lance l'application. Une application contient généralement de nombreux modules fonctionnels. L'AppModule
est défini dans le fichier app.module.ts
.
Le NgModule Router
Angular fournit un service qui vous permet de définir un chemin de navigation parmi les différents états d'application et hiérarchies de vues dans votre application. Le RouterModule
est défini dans le fichier app-routing.module.ts
.
Pour les données ou la logique qui ne sont pas associées à une vue spécifique, et que vous souhaitez partager entre les composants, vous créez une classe de service. La définition de la classe de service est immédiatement précédée du décorateur @Injectable()
. Le décorateur fournit les métadonnées qui permettent à d'autres fournisseurs d'être injectés en tant que dépendances dans votre classe. L'injection de dépendances (DI) vous permet de maintenir vos classes de composants légères et efficaces. Elles ne récupèrent pas de données depuis le serveur, ne valident pas les saisies utilisateur, ou ne journalisent pas directement dans la console ; elles délèguent de telles tâches aux services.
Configuration des sourcemap
Le framework Angular traduit les fichiers TypeScript en code JavaScript en suivant les options du fichier tsconfig.json
, puis construit un projet avec la configuration angular.json
. En examinant le fichier angular.json
, nous avons observé une option pour activer ou désactiver un sourcemap. Selon la documentation Angular, la configuration par défaut a un fichier sourcemap activé pour les scripts et n'est pas masqué par défaut:
Généralement, les fichiers sourcemap sont utilisés à des fins de débogage car ils cartographient les fichiers générés à leurs fichiers d'origine. Par conséquent, il n'est pas recommandé de les utiliser en environnement de production. Lorsque les sourcemaps sont activés, cela améliore la lisibilité et facilite l'analyse des fichiers en reproduisant l'état d'origine du projet Angular. Cependant, s'ils sont désactivés, un examinateur peut toujours analyser manuellement un fichier JavaScript compilé en recherchant des modèles anti-sécurité.
De plus, un fichier JavaScript compilé avec un projet Angular peut être trouvé dans les outils de développement du navigateur → Sources (ou Debugger et Sources) → [id].main.js. Selon les options activées, ce fichier peut contenir la ligne suivante à la fin //# sourceMappingURL=[id].main.js.map
ou non, si l'option hidden est définie sur true. Cependant, si le sourcemap est désactivé pour les scripts, les tests deviennent plus complexes et nous ne pouvons pas obtenir le fichier. De plus, le sourcemap peut être activé pendant la construction du projet comme ng build --source-map
.
Liaison de données
La liaison fait référence au processus de communication entre un composant et sa vue correspondante. Elle est utilisée pour transférer des données vers et depuis le framework Angular. Les données peuvent être transmises de diverses manières, telles que par des événements, interpolation, propriétés, ou par le mécanisme de liaison bidirectionnelle. De plus, les données peuvent également être partagées entre des composants liés (relation parent-enfant) et entre deux composants non liés en utilisant la fonctionnalité Service.
Nous pouvons classer la liaison par flux de données :
Source de données vers cible de vue (inclut interpolation, propriétés, attributs, classes et styles); peut être appliqué en utilisant
[]
ou{{}}
dans le modèle;Cible de vue vers source de données (inclut événements); peut être appliqué en utilisant
()
dans le modèle;Bidirectionnelle; peut être appliqué en utilisant
[()]
dans le modèle.
La liaison peut être appelée sur des propriétés, des événements, des attributs, ainsi que sur tout membre public d'une directive source :
Propriété
Propriété de l'élément, Propriété du composant, Propriété de la directive
<img [alt]="hero.name" [src]="heroImageUrl">
Événement
Événement de l'élément, Événement du composant, Événement de la directive
<button type="button" (click)="onSave()">Save
Bidirectionnelle
Événement et propriété
<input [(ngModel)]="name">
Attribut
Attribut (l'exception)
<button type="button" [attr.aria-label]="help">help
Classe
Propriété de classe
<div [class.special]="isSpecial">Special
Style
Propriété de style
<button type="button" [style.color]="isSpecial ? 'red' : 'green'">
Modèle de sécurité Angular
La conception d'Angular inclut l'encodage ou la désinfection de toutes les données par défaut, ce qui rend de plus en plus difficile la découverte et l'exploitation de vulnérabilités XSS dans les projets Angular. Il existe deux scénarios distincts pour la manipulation des données :
Interpolation ou
{{user_input}}
- effectue un encodage sensible au contexte et interprète l'entrée utilisateur comme du texte ;
Résultat : <script>alert(1)</script><h1>test</h1>
2. Liaison aux propriétés, attributs, classes et styles ou [attribut]="user_input"
- effectue une désinfection en fonction du contexte de sécurité fourni.
Résultat : <div><h1>test</h1></div>
Il existe 6 types de SecurityContext
:
None
;HTML
est utilisé lors de l'interprétation de la valeur comme HTML ;STYLE
est utilisé lors de la liaison CSS dans la propriétéstyle
;URL
est utilisé pour les propriétés d'URL, telles que<a href>
;SCRIPT
est utilisé pour le code JavaScript ;RESOURCE_URL
comme une URL qui est chargée et exécutée comme du code, par exemple, dans<script src>
.
Vulnérabilités
Contournement des méthodes de confiance en matière de sécurité
Angular introduit une liste de méthodes pour contourner son processus de désinfection par défaut et indiquer qu'une valeur peut être utilisée en toute sécurité dans un contexte spécifique, comme dans les cinq exemples suivants :
bypassSecurityTrustUrl
est utilisé pour indiquer que la valeur donnée est une URL de style sûre :
bypassSecurityTrustResourceUrl
est utilisé pour indiquer que la valeur donnée est une URL de ressource sûre :
bypassSecurityTrustHtml
est utilisé pour indiquer que la valeur donnée est du HTML sûr. Notez que l'insertion d'élémentsscript
dans l'arbre DOM de cette manière ne les fera pas exécuter le code JavaScript contenu, en raison de la façon dont ces éléments sont ajoutés à l'arbre DOM.
bypassSecurityTrustScript
est utilisé pour indiquer que la valeur donnée est du JavaScript sûr. Cependant, nous avons constaté que son comportement est imprévisible, car nous n'avons pas pu exécuter de code JS dans les modèles en utilisant cette méthode.
bypassSecurityTrustStyle
est utilisé pour indiquer que la valeur donnée est du CSS sûr. L'exemple suivant illustre l'injection de CSS :
Angular fournit une méthode sanitize
pour désinfecter les données avant de les afficher dans les vues. Cette méthode utilise le contexte de sécurité fourni et nettoie l'entrée en conséquence. Il est cependant crucial d'utiliser le bon contexte de sécurité pour les données et le contexte spécifiques. Par exemple, l'application d'un désinfectant avec SecurityContext.URL
sur un contenu HTML ne protège pas contre les valeurs HTML dangereuses. Dans de tels scénarios, une mauvaise utilisation du contexte de sécurité pourrait entraîner des vulnérabilités XSS.
Injection HTML
Cette vulnérabilité se produit lorsque l'entrée utilisateur est liée à l'une des trois propriétés : innerHTML
, outerHTML
, ou iframe
srcdoc
. Alors que la liaison à ces attributs interprète le HTML tel quel, l'entrée est désinfectée en utilisant SecurityContext.HTML
. Ainsi, l'injection HTML est possible, mais le script entre sites (XSS) ne l'est pas.
Exemple d'utilisation de innerHTML
:
Le résultat est <div><h1>test</h1></div>
.
Injection de modèle
Rendu côté client (CSR)
Angular exploite des modèles pour construire des pages de manière dynamique. L'approche consiste à encapsuler des expressions de modèle pour qu'Angular les évalue entre doubles accolades ({{}}
). De cette manière, le framework offre des fonctionnalités supplémentaires. Par exemple, un modèle tel que {{1+1}}
s'afficherait comme 2.
En général, Angular échappe aux entrées utilisateur qui peuvent être confondues avec des expressions de modèle (par exemple, des caractères tels que `< > ' " ``). Cela signifie que des étapes supplémentaires sont nécessaires pour contourner cette restriction, comme l'utilisation de fonctions qui génèrent des objets de chaîne JavaScript pour éviter d'utiliser des caractères interdits. Cependant, pour y parvenir, nous devons tenir compte du contexte Angular, de ses propriétés et variables. Par conséquent, une attaque par injection de modèle peut apparaître comme suit:
Comme indiqué ci-dessus: constructor
fait référence à la portée de la propriété constructor
de l'objet, nous permettant d'invoquer le constructeur de String et d'exécuter un code arbitraire.
Rendu côté serveur (SSR)
Contrairement au CSR, qui se produit dans le DOM du navigateur, Angular Universal est responsable du SSR des fichiers de modèle. Ces fichiers sont ensuite livrés à l'utilisateur. Malgré cette distinction, Angular Universal applique les mêmes mécanismes de désinfection utilisés dans le CSR pour améliorer la sécurité du SSR. Une vulnérabilité d'injection de modèle dans le SSR peut être repérée de la même manière que dans le CSR, car le langage de modèle utilisé est le même.
Bien sûr, il existe également la possibilité d'introduire de nouvelles vulnérabilités d'injection de modèle lors de l'utilisation de moteurs de modèles tiers tels que Pug et Handlebars.
XSS
Interfaces DOM
Comme mentionné précédemment, nous pouvons accéder directement au DOM en utilisant l'interface Document. Si l'entrée de l'utilisateur n'est pas validée au préalable, cela peut entraîner des vulnérabilités de script entre sites (XSS).
Nous avons utilisé les méthodes document.write()
et document.createElement()
dans les exemples ci-dessous:
Classes Angular
Il existe des classes qui peuvent être utilisées pour travailler avec les éléments DOM dans Angular : ElementRef
, Renderer2
, Location
et Document
. Une description détaillée des deux dernières classes est donnée dans la section Redirections ouvertes. La principale différence entre les deux premières est que l'API Renderer2
fournit une couche d'abstraction entre l'élément DOM et le code du composant, tandis que ElementRef
ne fait que contenir une référence à l'élément. Par conséquent, selon la documentation d'Angular, l'API ElementRef
ne devrait être utilisée qu'en dernier recours lorsque l'accès direct au DOM est nécessaire.
ElementRef
contient la propriéténativeElement
, qui peut être utilisée pour manipuler les éléments DOM. Cependant, une utilisation incorrecte denativeElement
peut entraîner une vulnérabilité d'injection XSS, comme indiqué ci-dessous :
Malgré le fait que
Renderer2
fournit une API qui peut être utilisée en toute sécurité même lorsque l'accès direct aux éléments natifs n'est pas pris en charge, il présente toujours des failles de sécurité. AvecRenderer2
, il est possible de définir des attributs sur un élément HTML en utilisant la méthodesetAttribute()
, qui ne dispose d'aucun mécanisme de prévention XSS.
Pour définir la propriété d'un élément DOM, vous pouvez utiliser la méthode
Renderer2.setProperty()
et déclencher une attaque XSS :
Au cours de nos recherches, nous avons également examiné le comportement d'autres méthodes Renderer2
, telles que setStyle()
, createComment()
et setValue()
, par rapport aux injections XSS et CSS. Cependant, nous n'avons pas pu trouver de vecteurs d'attaque valides pour ces méthodes en raison de leurs limitations fonctionnelles.
jQuery
jQuery est une bibliothèque JavaScript rapide, petite et riche en fonctionnalités qui peut être utilisée dans le projet Angular pour aider à manipuler les objets DOM HTML. Cependant, comme on le sait, les méthodes de cette bibliothèque peuvent être exploitées pour provoquer une vulnérabilité XSS. Afin de discuter de la manière dont certaines méthodes jQuery vulnérables peuvent être exploitées dans les projets Angular, nous avons ajouté cette sous-section.
La méthode
html()
récupère le contenu HTML du premier élément dans l'ensemble des éléments correspondants ou définit le contenu HTML de chaque élément correspondant. Cependant, par conception, tout constructeur ou méthode jQuery qui accepte une chaîne HTML peut potentiellement exécuter du code. Cela peut se produire par l'injection de balises<script>
ou l'utilisation d'attributs HTML qui exécutent du code, comme le montre l'exemple suivant.
La méthode
jQuery.parseHTML()
utilise des méthodes natives pour convertir la chaîne en un ensemble de nœuds DOM, qui peuvent ensuite être insérés dans le document.
Comme mentionné précédemment, la plupart des API jQuery qui acceptent des chaînes HTML exécuteront des scripts inclus dans le HTML. La méthode jQuery.parseHTML()
ne lance pas de scripts dans le HTML analysé à moins que keepScripts
ne soit explicitement défini sur true
. Cependant, il est toujours possible dans la plupart des environnements d'exécuter des scripts de manière indirecte ; par exemple, via l'attribut <img onerror>
.
Last updated