# Angular {{#include ../../banners/hacktricks-training.md}} ## La Liste de Vérification Checklist [from here](https://lsgeurope.com/post/angular-security-checklist). * [ ] Angular est considéré comme un framework côté client et n'est pas censé fournir de protection côté serveur * [ ] Le sourcemap pour les scripts est désactivé dans la configuration du projet * [ ] Les entrées utilisateur non fiables sont toujours interpolées ou assainies avant d'être utilisées dans les templates * [ ] L'utilisateur n'a aucun contrôle sur les templates côté serveur ou côté client * [ ] Les entrées utilisateur non fiables sont assainies en utilisant un contexte de sécurité approprié avant d'être considérées comme fiables par l'application * [ ] Les méthodes `BypassSecurity*` ne sont pas utilisées avec des entrées non fiables * [ ] Les entrées utilisateur non fiables ne sont pas passées aux classes Angular telles que `ElementRef`, `Renderer2` et `Document`, ou à d'autres sinks JQuery/DOM ## Qu'est-ce qu'Angular Angular est un **framework** front-end **puissant** et **open-source** maintenu par **Google**. Il utilise **TypeScript** pour améliorer la lisibilité du code et le débogage. Avec de forts mécanismes de sécurité, Angular prévient les vulnérabilités courantes côté client comme **XSS** et **redirections ouvertes**. Il peut également être utilisé côté **serveur**, rendant les considérations de sécurité importantes des **deux côtés**. ## Architecture du framework Afin de mieux comprendre les bases d'Angular, passons en revue ses concepts essentiels. Un projet Angular commun ressemble généralement à : ```bash my-workspace/ ├── ... #workspace-wide configuration files ├── src │ ├── app │ │ ├── app.module.ts #defines the root module, that tells Angular how to assemble the application │ │ ├── app.component.ts #defines the logic for the application's root component │ │ ├── app.component.html #defines the HTML template associated with the root component │ │ ├── app.component.css #defines the base CSS stylesheet for the root component │ │ ├── app.component.spec.ts #defines a unit test for the root component │ │ └── app-routing.module.ts #provides routing capability for the application │ ├── lib │ │ └── src #library-specific configuration files │ ├── index.html #main HTML page, where the component will be rendered in │ └── ... #application-specific configuration files ├── angular.json #provides workspace-wide and project-specific configuration defaults └── tsconfig.json #provides the base TypeScript configuration for projects in the workspace ``` 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 des données et une logique d'application, et est associée à 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. Le `AppComponent` est défini dans le fichier `app.component.ts`. Les NgModules Angular déclarent un contexte de compilation pour un ensemble de composants qui est 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. Le `AppModule` est défini dans le fichier `app.module.ts`. Le NgModule `Router` d'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 d'une 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épendance (DI) vous permet de garder vos classes de composants légères et efficaces. Elles ne récupèrent pas de données du serveur, ne valident pas les entrées utilisateur, ou ne se connectent pas directement à la console ; elles délèguent de telles tâches aux services. ## Configuration de sourcemap Le framework Angular traduit les fichiers TypeScript en code JavaScript en suivant les options de `tsconfig.json` et construit ensuite un projet avec la configuration `angular.json`. En regardant 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 caché par défaut : ```json "sourceMap": { "scripts": true, "styles": true, "vendor": false, "hidden": false } ``` Généralement, les fichiers sourcemap sont utilisés à des fins de débogage car ils associent les fichiers générés à leurs fichiers d'origine. Par conséquent, il n'est pas recommandé de les utiliser dans un environnement de production. Si les sourcemaps sont activés, cela améliore la lisibilité et aide à 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 motifs 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 Débogueur 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 il peut ne pas l'avoir, si l'option **hidden** est définie sur **true**. Néanmoins, si le sourcemap est désactivé pour **scripts**, les tests deviennent plus complexes, et nous ne pouvons pas obtenir le fichier. De plus, le sourcemap peut être activé lors de 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 par divers moyens, tels que par le biais d'événements, d'interpolation, de 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 et des attributs, ainsi que sur tout membre public d'une directive source : | TYPE | CIBLE | EXEMPLES | | --------- | -------------------------------------------------------- | -------------------------------------------------------------------- | | Propriété | Propriété d'élément, Propriété de composant, Propriété de directive | \ | | Événement | Événement d'élément, Événement de composant, Événement de directive | \ ``` * 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 : ```tsx //app.component.ts import {Component, Renderer2, ElementRef, ViewChild, AfterViewInit } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { public constructor ( private renderer2: Renderer2 ){} @ViewChild("img") img!: ElementRef; setProperty(){ this.renderer2.setProperty(this.img.nativeElement, 'innerHTML', ''); } } //app.component.html ``` Au cours de nos recherches, nous avons également examiné le comportement d'autres méthodes `Renderer2`, telles que `setStyle()`, `createComment()`, et `setValue()`, en relation avec les 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, légère et riche en fonctionnalités qui peut être utilisée dans le projet Angular pour aider à manipuler les objets DOM HTML. Cependant, comme il est connu, les méthodes de cette bibliothèque peuvent être exploitées pour atteindre une vulnérabilité XSS. Afin de discuter de la manière dont certaines méthodes jQuery vulnérables peuvent être exploitées dans des projets Angular, nous avons ajouté cette sous-section. * La méthode `html()` obtient 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 injection de balises `"); }); } } //app.component.html

some text here

``` * 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. ```tsx jQuery.parseHTML(data [, context ] [, keepScripts ]) ``` Comme mentionné précédemment, la plupart des API jQuery qui acceptent des chaînes HTML exécuteront des scripts qui sont inclus dans le HTML. La méthode `jQuery.parseHTML()` ne lance pas de scripts dans le HTML analysé à moins que `keepScripts` ne soit explicitement `true`. Cependant, il est toujours possible dans la plupart des environnements d'exécuter des scripts indirectement ; par exemple, via l'attribut ``. ```tsx //app.component.ts import { Component, OnInit } from '@angular/core'; import * as $ from 'jquery'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { ngOnInit() { $("button").on("click", function() { var $palias = $("#palias"), str = "", html = $.parseHTML(str), nodeNames = []; $palias.append(html); }); } } //app.component.html

some text

``` ### Open redirects #### Interfaces DOM Selon la documentation W3C, les objets `window.location` et `document.location` sont traités comme des alias dans les navigateurs modernes. C'est pourquoi ils ont une mise en œuvre similaire de certaines méthodes et propriétés, ce qui pourrait causer un redirection ouverte et un XSS DOM avec des attaques au schéma `javascript://` comme mentionné ci-dessous. * `window.location.href`(et `document.location.href`) La manière canonique d'obtenir l'objet de localisation DOM actuel est d'utiliser `window.location`. Il peut également être utilisé pour rediriger le navigateur vers une nouvelle page. En conséquence, avoir le contrôle sur cet objet nous permet d'exploiter une vulnérabilité de redirection ouverte. ```tsx //app.component.ts ... export class AppComponent { goToUrl(): void { window.location.href = "https://google.com/about" } } //app.component.html ``` Le processus d'exploitation est identique pour les scénarios suivants. * `window.location.assign()`(et `document.location.assign()`) Cette méthode fait en sorte que la fenêtre charge et affiche le document à l'URL spécifiée. Si nous avons le contrôle sur cette méthode, cela pourrait être un point d'entrée pour une attaque de redirection ouverte. ```tsx //app.component.ts ... export class AppComponent { goToUrl(): void { window.location.assign("https://google.com/about") } } ``` * `window.location.replace()`(et `document.location.replace()`) Cette méthode remplace la ressource actuelle par celle à l'URL fournie. Cela diffère de la méthode `assign()` en ce sens qu'après avoir utilisé `window.location.replace()`, la page actuelle ne sera pas enregistrée dans l'historique de session. Cependant, il est également possible d'exploiter une vulnérabilité de redirection ouverte lorsque nous avons le contrôle sur cette méthode. ```tsx //app.component.ts ... export class AppComponent { goToUrl(): void { window.location.replace("http://google.com/about") } } ``` * `window.open()` La méthode `window.open()` prend une URL et charge la ressource qu'elle identifie dans un nouvel onglet ou une nouvelle fenêtre existante. Avoir le contrôle sur cette méthode pourrait également être une opportunité de déclencher une vulnérabilité XSS ou de redirection ouverte. ```tsx //app.component.ts ... export class AppComponent { goToUrl(): void { window.open("https://google.com/about", "_blank") } } ``` #### Classes Angular * Selon la documentation Angular, `Document` Angular est le même que le document DOM, ce qui signifie qu'il est possible d'utiliser des vecteurs communs pour le document DOM afin d'exploiter des vulnérabilités côté client dans Angular. Les propriétés et méthodes `Document.location` pourraient être des points d'entrée pour des attaques de redirection ouverte réussies comme montré dans l'exemple : ```tsx //app.component.ts import { Component, Inject } from '@angular/core'; import { DOCUMENT } from '@angular/common'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { constructor(@Inject(DOCUMENT) private document: Document) { } goToUrl(): void { this.document.location.href = 'https://google.com/about'; } } //app.component.html ``` * Au cours de la phase de recherche, nous avons également examiné la classe `Location` d'Angular pour des vulnérabilités de redirection ouverte, mais aucun vecteur valide n'a été trouvé. `Location` est un service Angular que les applications peuvent utiliser pour interagir avec l'URL actuelle du navigateur. Ce service a plusieurs méthodes pour manipuler l'URL donnée - `go()`, `replaceState()`, et `prepareExternalUrl()`. Cependant, nous ne pouvons pas les utiliser pour rediriger vers un domaine externe. Par exemple : ```tsx //app.component.ts import { Component, Inject } from '@angular/core'; import {Location, LocationStrategy, PathLocationStrategy} from '@angular/common'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], providers: [Location, {provide: LocationStrategy, useClass: PathLocationStrategy}], }) export class AppComponent { location: Location; constructor(location: Location) { this.location = location; } goToUrl(): void { console.log(this.location.go("http://google.com/about")); } } ``` Résultat : `http://localhost:4200/http://google.com/about` * La classe `Router` d'Angular est principalement utilisée pour naviguer au sein du même domaine et n'introduit aucune vulnérabilité supplémentaire à l'application : ```jsx //app-routing.module.ts const routes: Routes = [ { path: '', redirectTo: 'https://google.com', pathMatch: 'full' }] ``` Résultat : `http://localhost:4200/https:` Les méthodes suivantes naviguent également dans le cadre du domaine : ```jsx const routes: Routes = [ { path: '', redirectTo: 'ROUTE', pathMatch: 'prefix' } ] this.router.navigate(['PATH']) this.router.navigateByUrl('URL') ``` ## Références * [Angular](https://angular.io/) * [Angular Security: The Definitive Guide (Part 1)](https://lsgeurope.com/post/angular-security-the-definitive-guide-part-1) * [Angular Security: The Definitive Guide (Part 2)](https://lsgeurope.com/post/angular-security-the-definitive-guide-part-2) * [Angular Security: The Definitive Guide (Part 3)](https://lsgeurope.com/post/angular-security-the-definitive-guide-part-3) * [Angular Security: Checklist](https://lsgeurope.com/post/angular-security-checklist) * [Workspace and project file structure](https://angular.io/guide/file-structure) * [Introduction to components and templates](https://angular.io/guide/architecture-components) * [Source map configuration](https://angular.io/guide/workspace-config#source-map-configuration) * [Binding syntax](https://angular.io/guide/binding-syntax) * [Angular Context: Easy Data-Binding for Nested Component Trees and the Router Outlet](https://medium.com/angular-in-depth/angular-context-easy-data-binding-for-nested-component-trees-and-the-router-outlet-a977efacd48) * [Sanitization and security contexts](https://angular.io/guide/security#sanitization-and-security-contexts) * [GitHub - angular/dom\_security\_schema.ts](https://github.com/angular/angular/blob/main/packages/compiler/src/schema/dom\_security\_schema.ts) * [XSS in Angular and AngularJS](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/XSS%20Injection/XSS%20in%20Angular.md) * [Angular Universal](https://angular.io/guide/universal) * [DOM XSS](https://book.hacktricks.wiki/en/pentesting-web/xss-cross-site-scripting/dom-xss.html) * [Angular ElementRef](https://angular.io/api/core/ElementRef) * [Angular Renderer2](https://angular.io/api/core/Renderer2) * [Renderer2 Example: Manipulating DOM in Angular - TekTutorialsHub](https://www.tektutorialshub.com/angular/renderer2-angular/) * [jQuery API Documentation](http://api.jquery.com/) * [How To Use jQuery With Angular (When You Absolutely Have To)](https://blog.bitsrc.io/how-to-use-jquery-with-angular-when-you-absolutely-have-to-42c8b6a37ff9) * [Angular Document](https://angular.io/api/common/DOCUMENT) * [Angular Location](https://angular.io/api/common/Location) * [Angular Router](https://angular.io/api/router/Router) {{#include ../../banners/hacktricks-training.md}}