# Angular {{#include ../../banners/hacktricks-training.md}} ## The Checklist Checklist [from here](https://lsgeurope.com/post/angular-security-checklist). * [ ] Angular被认为是一个客户端框架,不期望提供服务器端保护 * [ ] 项目配置中禁用了脚本的源映射 * [ ] 不可信的用户输入在用于模板之前始终被插值或清理 * [ ] 用户无法控制服务器端或客户端模板 * [ ] 不可信的用户输入在被应用程序信任之前,使用适当的安全上下文进行清理 * [ ] 不使用不可信输入的`BypassSecurity*`方法 * [ ] 不可信的用户输入不会传递给Angular类,如`ElementRef`、`Renderer2`和`Document`,或其他JQuery/DOM接收器 ## What is Angular Angular是一个**强大**且**开源**的前端框架,由**Google**维护。它使用**TypeScript**来增强代码的可读性和调试能力。凭借强大的安全机制,Angular防止常见的客户端漏洞,如**XSS**和**开放重定向**。它也可以在**服务器端**使用,因此从**两个角度**考虑安全性非常重要。 ## Framework architecture 为了更好地理解Angular的基础知识,让我们了解其基本概念。 常见的Angular项目通常看起来像: ```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 ``` 根据文档,每个 Angular 应用程序至少有一个组件,即根组件 (`AppComponent`),它将组件层次结构与 DOM 连接。每个组件定义一个包含应用程序数据和逻辑的类,并与定义要在目标环境中显示的视图的 HTML 模板相关联。`@Component()` 装饰器将其下方的类标识为组件,并提供模板和相关的组件特定元数据。`AppComponent` 在 `app.component.ts` 文件中定义。 Angular NgModules 声明一个编译上下文,用于一组专用于应用程序域、工作流或紧密相关功能的组件。每个 Angular 应用程序都有一个根模块,通常命名为 `AppModule`,它提供启动机制以启动应用程序。一个应用程序通常包含多个功能模块。`AppModule` 在 `app.module.ts` 文件中定义。 Angular `Router` NgModule 提供了一项服务,让您可以定义应用程序中不同状态和视图层次结构之间的导航路径。`RouterModule` 在 `app-routing.module.ts` 文件中定义。 对于不与特定视图相关联且希望在组件之间共享的数据或逻辑,您可以创建一个服务类。服务类定义前面会有 `@Injectable()` 装饰器。该装饰器提供元数据,允许其他提供者作为依赖项注入到您的类中。依赖注入 (DI) 使您能够保持组件类的精简和高效。它们不会从服务器获取数据、验证用户输入或直接记录到控制台;它们将此类任务委托给服务。 ## Sourcemap 配置 Angular 框架通过遵循 `tsconfig.json` 选项将 TypeScript 文件转换为 JavaScript 代码,然后使用 `angular.json` 配置构建项目。查看 `angular.json` 文件时,我们观察到一个选项可以启用或禁用 sourcemap。根据 Angular 文档,默认配置为脚本启用了 sourcemap 文件,并且默认情况下不隐藏: ```json "sourceMap": { "scripts": true, "styles": true, "vendor": false, "hidden": false } ``` 一般来说,sourcemap 文件用于调试目的,因为它们将生成的文件映射到其原始文件。因此,不建议在生产环境中使用它们。如果启用了 sourcemaps,它可以提高可读性并通过复制 Angular 项目的原始状态来帮助文件分析。然而,如果它们被禁用,审查者仍然可以通过搜索反安全模式手动分析编译后的 JavaScript 文件。 此外,带有 Angular 项目的编译 JavaScript 文件可以在浏览器开发者工具 → Sources(或 Debugger 和 Sources)→ \[id].main.js 中找到。根据启用的选项,该文件末尾可能包含以下行 `//# sourceMappingURL=[id].main.js.map`,如果 **hidden** 选项设置为 **true**,则可能不包含此行。尽管如此,如果 **scripts** 的 sourcemap 被禁用,测试将变得更加复杂,我们无法获取该文件。此外,sourcemap 可以在项目构建期间启用,例如 `ng build --source-map`。 ## 数据绑定 绑定是指组件与其对应视图之间的通信过程。它用于在 Angular 框架中传输数据。数据可以通过多种方式传递,例如通过事件、插值、属性或通过双向绑定机制。此外,数据还可以在相关组件(父子关系)之间以及在两个不相关的组件之间使用服务功能进行共享。 我们可以按数据流对绑定进行分类: * 数据源到视图目标(包括 _interpolation_、_properties_、_attributes_、_classes_ 和 _styles_);可以通过在模板中使用 `[]` 或 `{{}}` 来应用; * 视图目标到数据源(包括 _events_);可以通过在模板中使用 `()` 来应用; * 双向;可以通过在模板中使用 `[()]` 来应用。 绑定可以在属性、事件和属性上调用,以及在源指令的任何公共成员上调用: | 类型 | 目标 | 示例 | | --------- | ------------------------------------------------------ | ------------------------------------------------------------------ | | 属性 | 元素属性、组件属性、指令属性 | \ | | 事件 | 元素事件、组件事件、指令事件 | \ ``` * 要设置 DOM 元素的属性,可以使用 `Renderer2.setProperty()` 方法并触发 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 ``` 在我们的研究中,我们还检查了其他 `Renderer2` 方法的行为,例如 `setStyle()`、`createComment()` 和 `setValue()`,与 XSS 和 CSS 注入的关系。然而,由于它们的功能限制,我们未能找到这些方法的有效攻击向量。 #### jQuery jQuery 是一个快速、小巧且功能丰富的 JavaScript 库,可以在 Angular 项目中用于操作 HTML DOM 对象。然而,众所周知,该库的方法可能被利用以实现 XSS 漏洞。为了讨论一些易受攻击的 jQuery 方法如何在 Angular 项目中被利用,我们添加了这一小节。 * `html()` 方法获取匹配元素集合中第一个元素的 HTML 内容,或设置每个匹配元素的 HTML 内容。然而,按设计,任何接受 HTML 字符串的 jQuery 构造函数或方法都可能执行代码。这可能通过注入 `"); }); } } //app.component.html

some text here

``` * `jQuery.parseHTML()` 方法使用本地方法将字符串转换为一组 DOM 节点,然后可以将其插入到文档中。 ```tsx jQuery.parseHTML(data [, context ] [, keepScripts ]) ``` 如前所述,大多数接受 HTML 字符串的 jQuery API 将运行包含在 HTML 中的脚本。`jQuery.parseHTML()` 方法不会在解析的 HTML 中运行脚本,除非 `keepScripts` 显式为 `true`。然而,在大多数环境中,仍然可以间接执行脚本;例如,通过 `` 属性。 ```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 #### DOM 接口 根据 W3C 文档,`window.location` 和 `document.location` 对象在现代浏览器中被视为别名。这就是为什么它们在某些方法和属性的实现上相似,这可能导致开放重定向和 DOM XSS 与 `javascript://` 架构攻击,如下所述。 * `window.location.href`(和 `document.location.href`) 获取当前 DOM 位置对象的规范方法是使用 `window.location`。它也可以用于将浏览器重定向到新页面。因此,控制该对象使我们能够利用开放重定向漏洞。 ```tsx //app.component.ts ... export class AppComponent { goToUrl(): void { window.location.href = "https://google.com/about" } } //app.component.html ``` 以下场景的利用过程是相同的。 * `window.location.assign()`(和 `document.location.assign()`) 此方法使窗口加载并显示指定 URL 的文档。如果我们控制此方法,它可能是开放重定向攻击的一个出口。 ```tsx //app.component.ts ... export class AppComponent { goToUrl(): void { window.location.assign("https://google.com/about") } } ``` * `window.location.replace()`(和 `document.location.replace()`) 此方法用提供的 URL 中的资源替换当前资源。 与 `assign()` 方法的不同之处在于,使用 `window.location.replace()` 后,当前页面不会保存在会话历史中。然而,当我们控制此方法时,也可以利用开放重定向漏洞。 ```tsx //app.component.ts ... export class AppComponent { goToUrl(): void { window.location.replace("http://google.com/about") } } ``` * `window.open()` `window.open()` 方法接受一个 URL,并将其识别的资源加载到新标签或现有标签中。控制此方法也可能是触发 XSS 或开放重定向漏洞的机会。 ```tsx //app.component.ts ... export class AppComponent { goToUrl(): void { window.open("https://google.com/about", "_blank") } } ``` #### Angular 类 * 根据 Angular 文档,Angular `Document` 与 DOM 文档相同,这意味着可以使用常见的向量来利用 Angular 中的客户端漏洞。`Document.location` 属性和方法可能是成功开放重定向攻击的出口,如示例所示: ```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 ``` * 在研究阶段,我们还审查了 Angular `Location` 类的开放重定向漏洞,但未发现有效向量。`Location` 是一个 Angular 服务,应用程序可以使用它与浏览器的当前 URL 进行交互。该服务有几个方法来操作给定的 URL - `go()`、`replaceState()` 和 `prepareExternalUrl()`。然而,我们无法使用它们进行重定向到外部域。例如: ```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")); } } ``` 结果:`http://localhost:4200/http://google.com/about` * Angular `Router` 类主要用于在同一域内导航,并不会给应用程序引入任何额外的漏洞: ```jsx //app-routing.module.ts const routes: Routes = [ { path: '', redirectTo: 'https://google.com', pathMatch: 'full' }] ``` 结果:`http://localhost:4200/https:` 以下方法也在域的范围内导航: ```jsx const routes: Routes = [ { path: '', redirectTo: 'ROUTE', pathMatch: 'prefix' } ] this.router.navigate(['PATH']) this.router.navigateByUrl('URL') ``` ## 参考文献 * [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}}