Redirect-Parameter (returnUrl, next, redirectTo) sind ein klassischer Open-Redirect-Vektor: Ein Angreifer baut einen Login-Link, dessen returnUrl auf eine externe Phishing-Domain zeigt, und navigiert die App nach der Authentifizierung blind dorthin, werden Nutzer stillschweigend weitergeleitet. Dieser Service erzwingt eine Präfix-Allowlist, weist protokollrelative URLs (//evil.com, die Browser als absolute URL desselben Schemas behandeln) sowie jede URL mit explizitem Schema ausdrücklich zurück und fällt auf einen sicheren Standardwert zurück, sobald die Eingabe die Validierung nicht besteht oder sich nicht einmal URI-dekodieren lässt.
import { Injectable, inject } from '@angular/core';import { Router, UrlTree } from '@angular/router';const ALLOWED_INTERNAL_PREFIX = '/app/';@Injectable({ providedIn: 'root' })class SafeRedirectService {private router = inject(Router);resolveSafeTarget(rawReturnUrl: string | null): UrlTree {if (!rawReturnUrl) {return this.router.parseUrl('/app/home');}let decoded: string;try {decoded = decodeURIComponent(rawReturnUrl);} catch {return this.router.parseUrl('/app/home');}const isProtocolRelative = decoded.startsWith('//');const isAbsoluteUrl = /^[a-z][a-z0-9+.-]*:/i.test(decoded);const isInternal = decoded.startsWith(ALLOWED_INTERNAL_PREFIX);if (isProtocolRelative || isAbsoluteUrl || !isInternal) {return this.router.parseUrl('/app/home');}return this.router.parseUrl(decoded);}}