# Angular ## The Checklist Checklist [from here](https://lsgeurope.com/post/angular-security-checklist). * [ ] Angular вважається фреймворком на стороні клієнта і не очікується, що він забезпечить захист на стороні сервера * [ ] Sourcemap для скриптів вимкнено в конфігурації проекту * [ ] Ненадійний ввід користувача завжди інтерполюється або очищається перед використанням у шаблонах * [ ] Користувач не має контролю над шаблонами на стороні сервера або клієнта * [ ] Ненадійний ввід користувача очищається з використанням відповідного контексту безпеки перед тим, як бути довіреним додатком * [ ] `BypassSecurity*` методи не використовуються з ненадійним ввідом * [ ] Ненадійний ввід користувача не передається в класи Angular, такі як `ElementRef`, `Renderer2` та `Document`, або інші JQuery/DOM sinks ## What is Angular Angular є **потужним** і **відкритим** фреймворком для фронтенду, який підтримується **Google**. Він використовує **TypeScript** для покращення читабельності коду та налагодження. Завдяки сильним механізмам безпеки, Angular запобігає поширеним вразливостям на стороні клієнта, таким як **XSS** та **відкриті перенаправлення**. Його також можна використовувати на **стороні сервера**, що робить питання безпеки важливими з **обох сторін**. ## Framework architecture In order to better understand the Angular basics, let’s go through its essential concepts. Common Angular project usually looks like: ```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`. NgModule Angular `Router` надає сервіс, який дозволяє визначити навігаційний шлях серед різних станів додатка та ієрархій виглядів у вашому додатку. `RouterModule` визначено у файлі `app-routing.module.ts`. Для даних або логіки, які не пов'язані з конкретним виглядом і які ви хочете поділитися між компонентами, ви створюєте клас сервісу. Визначення класу сервісу безпосередньо передує декоратору `@Injectable()`. Декоратор надає метадані, які дозволяють іншим провайдерам бути впровадженими як залежності у ваш клас. Впровадження залежностей (DI) дозволяє зберігати ваші класи компонентів стрункими та ефективними. Вони не отримують дані з сервера, не перевіряють введення користувача і не ведуть безпосередній лог до консолі; вони делегують такі завдання сервісам. ## Налаштування sourcemap Фреймворк Angular перекладає файли TypeScript у JavaScript-код, дотримуючись параметрів `tsconfig.json`, а потім будує проект з конфігурацією `angular.json`. Розглядаючи файл `angular.json`, ми спостерігали опцію для увімкнення або вимкнення sourcemap. Згідно з документацією Angular, за замовчуванням конфігурація має файл sourcemap, увімкнений для скриптів, і за замовчуванням не прихований: ```json "sourceMap": { "scripts": true, "styles": true, "vendor": false, "hidden": false } ``` Загалом, файли sourcemap використовуються для налагодження, оскільки вони відображають згенеровані файли на їх оригінальні файли. Тому не рекомендується використовувати їх у виробничому середовищі. Якщо sourcemaps увімкнено, це покращує читабельність і допомагає в аналізі файлів, відтворюючи оригінальний стан проекту Angular. Однак, якщо вони вимкнені, рецензент все ще може вручну проаналізувати скомпільований JavaScript файл, шукаючи антибезпекові шаблони. Більш того, скомпільований JavaScript файл з проектом Angular можна знайти в інструментах розробника браузера → Sources (або Debugger і Sources) → \[id].main.js. Залежно від увімкнених опцій, цей файл може містити наступний рядок в кінці `//# sourceMappingURL=[id].main.js.map` або може не містити, якщо опція **hidden** встановлена на **true**. Проте, якщо sourcemap вимкнено для **scripts**, тестування стає більш складним, і ми не можемо отримати файл. Крім того, sourcemap може бути увімкнено під час збірки проекту, наприклад, `ng build --source-map`. ## Прив'язка даних Прив'язка відноситься до процесу комунікації між компонентом і відповідним виглядом. Вона використовується для передачі даних до та з фреймворку Angular. Дані можуть передаватися різними способами, такими як через події, інтерполяцію, властивості або через механізм двосторонньої прив'язки. Більш того, дані також можуть бути спільними між пов'язаними компонентами (відношення батька і дитини) та між двома непов'язаними компонентами за допомогою функції Service. Ми можемо класифікувати прив'язку за потоком даних: * Джерело даних до цільового вигляду (включає _інтерполяцію_, _властивості_, _атрибути_, _класи_ та _стилі_); може бути застосовано за допомогою `[]` або `{{}}` у шаблоні; * Цільовий вигляд до джерела даних (включає _події_); може бути застосовано за допомогою `()` у шаблоні; * Двостороння; може бути застосовано за допомогою `[()]` у шаблоні. Прив'язка може бути викликана на властивостях, подіях і атрибутах, а також на будь-якому публічному члені директиви джерела: | TYPE | TARGET | EXAMPLES | | --------- | -------------------------------------------------------- | -------------------------------------------------------------------- | | Property | Властивість елемента, Властивість компонента, Властивість директиви | \ | | Event | Подія елемента, Подія компонента, Подія директиви | \ ``` * Щоб встановити властивість елемента 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 вміст кожного відповідного елемента. Однак за дизайном будь-який конструктор або метод jQuery, який приймає HTML рядок, може потенційно виконувати код. Це може статися через ін'єкцію `"); }); } } //app.component.html

some text here

``` * Метод `jQuery.parseHTML()` використовує рідні методи для перетворення рядка в набір DOM вузлів, які потім можуть бути вставлені в документ. ```tsx jQuery.parseHTML(data [, context ] [, keepScripts ]) ``` Як вже згадувалося, більшість API jQuery, які приймають HTML рядки, виконуватимуть скрипти, які включені в 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, що означає, що можна використовувати загальні вектори для документа 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)