31 KiB
Angular
La liste de vérification
Vérifiez que :
- Angular est considéré comme un framework côté client et n'est pas censé fournir une protection côté serveur
- Les sourcemaps pour les scripts sont désactivés dans la configuration du projet
- Les entrées utilisateur non fiables sont toujours interpolées ou désinfectées 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 désinfectées 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 transmises aux classes Angular telles que
ElementRef
,Renderer2
etDocument
, ou à d'autres sources JQuery/DOM
Qu'est-ce que Angular
Angular est un puissant framework côté client largement utilisé pour construire des applications web dynamiques. Il est open-source et maintenu par Google. L'une des principales caractéristiques d'Angular est son utilisation de TypeScript, un sur-ensemble typé de JavaScript qui rend le code plus facile à lire, à maintenir et à déboguer.
Les mécanismes de sécurité d'Angular sont conçus pour prévenir les vulnérabilités courantes côté client, notamment les attaques de type cross-site scripting (XSS) et les redirections ouvertes. Cependant, Angular peut également être utilisé côté serveur pour générer des pages statiques. Ainsi, la sécurité d'Angular doit être prise en compte des deux côtés.
Architecture du framework
Pour mieux comprendre les bases d'Angular, passons en revue ses concepts essentiels.
Un projet Angular classique ressemble généralement à :
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 relie une hiérarchie de composants au 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. 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 dédiés à un domaine d'application, un flux de travail ou un ensemble de fonctionnalités étroitement liées. Chaque application Angular a un module racine, conventionnellement appelé AppModule
, qui fournit le mécanisme de démarrage de l'application. Une application contient généralement plusieurs 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 entre les différents états d'application et hiérarchies de vues de 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 aux autres fournisseurs d'être injectés en tant que dépendances dans votre classe. L'injection de dépendances (DI) vous permet de garder 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 entrées utilisateur ou ne se connectent pas directement à la console ; elles délèguent ces tâches à des services.
Configuration des sourcemaps
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 active un fichier sourcemap pour les scripts et n'est pas masquée par défaut :
"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 permettent de faire correspondre 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ées, cela améliore la lisibilité et facilite l'analyse des fichiers en reproduisant l'état d'origine du projet Angular. Cependant, si elles sont désactivées, 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 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 il peut ne pas la contenir, si l'option hidden est définie sur true. Néanmoins, si la sourcemap est désactivée pour les scripts, les tests deviennent plus complexes et nous ne pouvons pas obtenir le fichier. De plus, la sourcemap peut être activée lors de la construction du projet avec ng build --source-map
.
Data binding
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 différentes manières, telles que par des événements, l'interpolation, les 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é de Service.
Nous pouvons classer la liaison par flux de données :
- Source de données vers cible de vue (inclut l'interpolation, les propriétés, les attributs, les classes et les styles) ; peut être appliqué en utilisant
[]
ou{{}}
dans le modèle ; - Cible de vue vers source de données (inclut les é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 utilisée sur des propriétés, des événements et des attributs, ainsi que sur n'importe quel membre public d'une directive source :
TYPE | CIBLE | EXEMPLES |
---|---|---|
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é d'Angular
La conception d'Angular inclut par défaut le codage ou la désinfection de toutes les données, 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 :
- L'interpolation ou
{{user_input}}
- effectue un encodage sensible au contexte et interprète la saisie de l'utilisateur comme du texte ;
//app.component.ts
test = "<script>alert(1)</script><h1>test</h1>";
//app.component.html
{{test}}
Résultat : <script>alert(1)</script><h1>test</h1>
2. La liaison aux propriétés, aux attributs, aux classes et aux styles ou [attribute]="user_input"
- effectue une désinfection en fonction du contexte de sécurité fourni.
//app.component.ts
test = "<script>alert(1)</script><h1>test</h1>";
//app.component.html
<div [innerHtml]="test"></div>
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 en tant que HTML ;STYLE
est utilisé lors de la liaison du CSS à 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
est utilisé comme URL qui est chargée et exécutée comme du code, par exemple, dans<script src>
.
Vulnérabilités
Contourner les méthodes de confiance 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ée pour indiquer que la valeur donnée est une URL de style sûre :
//app.component.ts
this.trustedUrl = this.sanitizer.bypassSecurityTrustUrl('javascript:alert()');
//app.component.html
<a class="e2e-trusted-url" [href]="trustedUrl">Cliquez ici</a>
//résultat
<a _ngcontent-pqg-c12="" class="e2e-trusted-url" href="javascript:alert()">Cliquez ici</a>
bypassSecurityTrustResourceUrl
est utilisée pour indiquer que la valeur donnée est une URL de ressource sûre :
//app.component.ts
this.trustedResourceUrl = this.sanitizer.bypassSecurityTrustResourceUrl("https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png");
//app.component.html
<iframe [src]="trustedResourceUrl"></iframe>
//résultat
<img _ngcontent-nre-c12="" src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png">
bypassSecurityTrustHtml
est utilisée pour indiquer que la valeur donnée est un 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 qu'ils contiennent, en raison de la façon dont ces éléments sont ajoutés à l'arbre DOM.
//app.component.ts
this.trustedHtml = this.sanitizer.bypassSecurityTrustHtml("<h1>balise html</h1><svg onclick=\"alert('bypassSecurityTrustHtml')\" style=display:block>blah</svg>");
//app.component.html
<p style="border:solid" [innerHtml]="trustedHtml"></p>
//résultat
<h1>balise html</h1>
<svg onclick="alert('bypassSecurityTrustHtml')" style="display:block">blah</svg>
bypassSecurityTrustScript
est utilisée 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.
//app.component.ts
this.trustedScript = this.sanitizer.bypassSecurityTrustScript("alert('bypass Security TrustScript')");
//app.component.html
<script [innerHtml]="trustedScript"></script>
//résultat
-
bypassSecurityTrustStyle
est utilisée pour indiquer que la valeur donnée est du CSS sûr. L'exemple suivant illustre l'injection de CSS :
//app.component.ts
this.trustedStyle = this.sanitizer.bypassSecurityTrustStyle('background-image: url(https://example.com/exfil/a)');
//app.component.html
<input type="password" name="pwd" value="01234" [style]="trustedStyle">
//résultat
Request URL: GET example.com/exfil/a
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 les entrées en conséquence. Il est cependant crucial d'utiliser le contexte de sécurité correct pour les données et le contexte spécifiques. Par exemple, l'application d'un désinfectant avec SecurityContext.URL
sur du 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 de l'utilisateur est liée à l'une des trois propriétés suivantes : innerHTML
, outerHTML
ou iframe
srcdoc
. Bien que la liaison à ces attributs interprète le HTML tel quel, l'entrée est nettoyée à l'aide de SecurityContext.HTML
. Ainsi, l'injection HTML est possible, mais le cross-site scripting (XSS) ne l'est pas.
Exemple d'utilisation de innerHTML
:
//app.component.ts
import { Component} from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent{
//define a variable with user input
test = "<script>alert(1)</script><h1>test</h1>";
}
//app.component.html
<div [innerHTML]="test"></div>
Le résultat est <div><h1>test</h1></div>
.
Injection de modèle
Rendu côté client (CSR)
Angular utilise des modèles pour construire des pages dynamiquement. L'approche consiste à encapsuler les expressions de modèle que Angular é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 pourraient être confondues avec des expressions de modèle (par exemple, les caractères `< > ' " ``). Cela signifie que des étapes supplémentaires sont nécessaires pour contourner cette restriction, telles que 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 prendre en compte le contexte d'Angular, ses propriétés et ses variables. Par conséquent, une attaque par injection de modèle peut apparaître comme suit :
//app.component.ts
const _userInput = '{{constructor.constructor(\'alert(1)\'()}}'
@Component({
selector: 'app-root',
template: '<h1>title</h1>' + _userInput
})
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 la chaîne de caractères et d'exécuter un code arbitraire.
Rendu côté serveur (SSR)
Contrairement à CSR, qui se produit dans le DOM du navigateur, Angular Universal est responsable du rendu côté serveur 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 sanitization utilisés dans CSR pour améliorer la sécurité du SSR. Une vulnérabilité d'injection de modèle dans SSR peut être repérée de la même manière que dans CSR, car le langage de modèle utilisé est le même.
Bien sûr, il est également possible d'introduire de nouvelles vulnérabilités d'injection de modèle lors de l'utilisation de moteurs de modèle tiers tels que Pug et Handlebars.
XSS
Interfaces DOM
Comme indiqué 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 cross-site scripting (XSS).
Nous avons utilisé les méthodes document.write()
et document.createElement()
dans les exemples ci-dessous:
//app.component.ts 1
import { Component} from '@angular/core';
@Component({
selector: 'app-root',
template: ''
})
export class AppComponent{
constructor () {
document.open();
document.write("<script>alert(document.domain)</script>");
document.close();
}
}
//app.component.ts 2
import { Component} from '@angular/core';
@Component({
selector: 'app-root',
template: ''
})
export class AppComponent{
constructor () {
var d = document.createElement('script');
var y = document.createTextNode("alert(1)");
d.appendChild(y);
document.body.appendChild(d);
}
}
//app.component.ts 3
import { Component} from '@angular/core';
@Component({
selector: 'app-root',
template: ''
})
export class AppComponent{
constructor () {
var a = document.createElement('img');
a.src='1';
a.setAttribute('onerror','alert(1)');
document.body.appendChild(a);
}
}
Classes Angular
Il existe quelques 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 doit ê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 le montre l'exemple suivant :
//app.component.ts
import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
...
constructor(private elementRef: ElementRef) {
const s = document.createElement('script');
s.type = 'text/javascript';
s.textContent = 'alert("Hello World")';
this.elementRef.nativeElement.appendChild(s);
}
}
- 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 quelques failles de sécurité. AvecRenderer2
, il est possible de définir des attributs sur un élément HTML à l'aide de la méthodesetAttribute()
, qui ne dispose d'aucun mécanisme de prévention XSS.
//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;
addAttribute(){
this.renderer2.setAttribute(this.img.nativeElement, 'src', '1');
this.renderer2.setAttribute(this.img.nativeElement, 'onerror', 'alert(1)');
}
}
//app.component.html
<img #img>
<button (click)="setAttribute()">Cliquez ici !</button>
- 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 :
//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', '<img src=1 onerror=alert(1)>');
}
}
//app.component.html
<a #a></a>
<button (click)="setProperty()">Cliquez ici !</button>
Lors de nos recherches, nous avons également examiné le comportement d'autres méthodes de Renderer2
, telles que setStyle()
, createComment()
et setValue()
, en ce qui concerne 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 un projet Angular pour faciliter la manipulation des objets DOM HTML. Cependant, comme on le sait, les méthodes de cette bibliothèque peuvent être exploitées pour créer une vulnérabilité XSS. Afin de discuter de la façon dont certaines méthodes vulnérables de jQuery 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.
//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()
{
$("p").html("<script>alert(1)</script>");
});
}
}
//app.component.html
<button>Cliquez ici</button>
<p>du texte ici</p>
- 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.
jQuery.parseHTML(data [, context ] [, keepScripts ])
Comme mentionné précédemment, la plupart des API jQuery qui acceptent des chaînes HTML exécuteront les scripts inclus dans le HTML. La méthode jQuery.parseHTML()
ne lance pas les 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 indirectement, par exemple via l'attribut <img onerror>
.
//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 = "<img src=1 onerror=alert(1)>",
html = $.parseHTML(str),
nodeNames = [];
$palias.append(html);
});
}
}
//app.component.html
<button>Cliquez ici</button>
<p id="palias">du texte</p>
Redirections ouvertes
Interfaces DOM
Selon la documentation du W3C, les objets window.location
et document.location
sont traités comme des alias dans les navigateurs modernes. C'est pourquoi ils ont une implémentation similaire de certaines méthodes et propriétés, ce qui peut entraîner une redirection ouverte et des attaques XSS DOM avec le schéma javascript://
, comme mentionné ci-dessous.
window.location.href
(etdocument.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. Ainsi, avoir le contrôle sur cet objet nous permet d'exploiter une vulnérabilité de redirection ouverte.
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.location.href = "https://google.com/about"
}
}
//app.component.html
<button type="button" (click)="goToUrl()">Cliquez ici !</button>
Le processus d'exploitation est identique pour les scénarios suivants.
window.location.assign()
(etdocument.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, elle peut être une faille pour une attaque de redirection ouverte.
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.location.assign("https://google.com/about")
}
}
window.location.replace()
(etdocument.location.replace()
)
Cette méthode remplace la ressource actuelle par celle fournie par l'URL spécifiée.
La différence avec la méthode assign()
est 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.
//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, ou dans un onglet ou une fenêtre existant(e). Avoir le contrôle sur cette méthode peut également être une opportunité pour déclencher une vulnérabilité XSS ou de redirection ouverte.
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.open("https://google.com/about", "_blank")
}
}
Classes Angular
- Selon la documentation Angular, la classe
Document
d'Angular est identique au 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éthodesDocument.location
peuvent être des points d'entrée pour des attaques de redirection ouverte réussies, comme le montre l'exemple suivant :
//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
<button type="button" (click)="goToUrl()">Cliquez ici !</button>
- Au cours de la phase de recherche, nous avons également examiné la classe
Location
d'Angular pour les 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 dispose de plusieurs méthodes pour manipuler l'URL donnée -go()
,replaceState()
etprepareExternalUrl()
. Cependant, nous ne pouvons pas les utiliser pour rediriger vers un domaine externe. Par exemple :
//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 dans le même domaine et n'introduit aucune vulnérabilité supplémentaire dans l'application :
//app-routing.module.ts
const routes: Routes = [
{ path: '', redirectTo: 'https://google.com', pathMatch: 'full' }]
Résultat : http://localhost:4200/https:
Les méthodes suivantes permettent également de naviguer dans le domaine :
const routes: Routes = [ { path: '', redirectTo: 'ROUTE', pathMatch: 'prefix' } ]
this.router.navigate(['PATH'])
this.router.navigateByUrl('URL')
Références
- Angular
- Angular Security: The Definitive Guide (Part 1)
- Angular Security: The Definitive Guide (Part 2)
- Angular Security: The Definitive Guide (Part 3)
- Angular Security: Checklist
- Workspace and project file structure
- Introduction to components and templates
- Source map configuration
- Binding syntax
- Angular Context: Easy Data-Binding for Nested Component Trees and the Router Outlet
- Sanitization and security contexts
- GitHub - angular/dom_security_schema.ts
- XSS in Angular and AngularJS
- Angular Universal
- DOM XSS
- Angular ElementRef
- Angular Renderer2
- Renderer2 Example: Manipulating DOM in Angular - TekTutorialsHub
- jQuery API Documentation
- How To Use jQuery With Angular (When You Absolutely Have To)
- Angular Document
- Angular Location
- Angular Router