mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-16 01:38:20 +00:00
Translated ['network-services-pentesting/pentesting-web/angular.md'] to
This commit is contained in:
parent
2a56523886
commit
c9592e6999
1 changed files with 564 additions and 0 deletions
564
network-services-pentesting/pentesting-web/angular.md
Normal file
564
network-services-pentesting/pentesting-web/angular.md
Normal file
|
@ -0,0 +1,564 @@
|
|||
# Angularセキュリティ
|
||||
|
||||
# チェックリスト
|
||||
|
||||
次のことを確認してください:
|
||||
|
||||
- [ ] Angularはクライアントサイドのフレームワークと見なされ、サーバーサイドの保護を提供することは期待されていません
|
||||
- [ ] プロジェクトの設定でスクリプトのソースマップが無効になっていることを確認する
|
||||
- [ ] 信頼できないユーザーの入力は、テンプレートで使用される前に常に補間またはサニタイズされていることを確認する
|
||||
- [ ] ユーザーはサーバーサイドまたはクライアントサイドのテンプレートを制御できないことを確認する
|
||||
- [ ] 信頼できないユーザーの入力は、アプリケーションに信頼される前に適切なセキュリティコンテキストを使用してサニタイズされていることを確認する
|
||||
- [ ] `BypassSecurity*` メソッドは信頼できない入力と一緒に使用されていないことを確認する
|
||||
- [ ] 信頼できないユーザーの入力は、`ElementRef`、`Renderer2`、`Document`などのAngularクラスや他のJQuery/DOMのシンクに渡されていないことを確認する
|
||||
|
||||
# Angularとは
|
||||
|
||||
Angularは、ダイナミックなWebアプリケーションを構築するために広く使用されている強力なフロントエンドフレームワークです。これはオープンソースであり、Googleによってメンテナンスされています。 Angularの主な特徴の1つは、TypeScriptの使用です。これはJavaScriptの型付きの上位セットであり、コードを読みやすく、保守しやすく、デバッグしやすくします。
|
||||
|
||||
Angularのセキュリティメカニズムは、クロスサイトスクリプティング(XSS)やオープンリダイレクトなどの一般的なクライアントサイドの脆弱性を防ぐように設計されています。ただし、Angularはサーバーサイドでも使用され、静的ページを生成するために使用されることもあります。したがって、Angularのセキュリティは両方の側面から考慮する必要があります。
|
||||
|
||||
# フレームワークのアーキテクチャ
|
||||
|
||||
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アプリケーションの構成要素
|
||||
|
||||
ドキュメントによると、すべてのAngularアプリケーションには少なくとも1つのコンポーネント、ルートコンポーネント(`AppComponent`)があり、コンポーネントの階層をDOMと接続します。各コンポーネントは、アプリケーションのデータとロジックを含むクラスを定義し、表示するビューを定義するHTMLテンプレートと関連するコンポーネント固有のメタデータと関連付けられます。`@Component()`デコレータは、直下のクラスをコンポーネントとして識別し、テンプレートと関連するコンポーネント固有のメタデータを提供します。`AppComponent`は`app.component.ts`ファイルで定義されています。
|
||||
|
||||
AngularのNgModuleは、アプリケーションドメイン、ワークフロー、または関連する機能セットに専用のコンポーネントセットのコンパイルコンテキストを宣言します。すべてのAngularアプリケーションには、通常、多くの機能モジュールが含まれています。`AppModule`は、アプリケーションを起動するブートストラップメカニズムを提供する、慣例的に`AppModule`という名前のルートモジュールです。`AppModule`は`app.module.ts`ファイルで定義されています。
|
||||
|
||||
Angularの`Router`NgModuleは、アプリケーションの異なる状態とビューの階層間のナビゲーションパスを定義するためのサービスを提供します。`RouterModule`は`app-routing.module.ts`ファイルで定義されています。
|
||||
|
||||
特定のビューに関連付けられていないデータやロジック、およびコンポーネント間で共有したいものについては、サービスクラスを作成します。サービスクラスの定義の直前には、`@Injectable()`デコレータが付けられます。このデコレータは、他のプロバイダを依存関係としてクラスに注入できるようにするメタデータを提供します。依存性注入(DI)を使用すると、コンポーネントクラスをスリムで効率的に保つことができます。コンポーネントクラスはサーバーからデータを取得したり、ユーザーの入力を検証したり、直接コンソールにログを出力したりしません。これらのタスクはサービスに委任されます。
|
||||
|
||||
# ソースマップの設定
|
||||
|
||||
Angularフレームワークは、TypeScriptファイルを`tsconfig.json`オプションに従ってJavaScriptコードに変換し、`angular.json`の設定に従ってプロジェクトをビルドします。`angular.json`ファイルを見ると、ソースマップを有効または無効にするオプションがあることがわかりました。Angularのドキュメントによると、デフォルトの設定では、スクリプト用のソースマップファイルが有効になっており、デフォルトでは非表示になっていません。
|
||||
```json
|
||||
"sourceMap": {
|
||||
"scripts": true,
|
||||
"styles": true,
|
||||
"vendor": false,
|
||||
"hidden": false
|
||||
}
|
||||
```
|
||||
一般的に、ソースマップファイルはデバッグ目的で使用され、生成されたファイルを元のファイルにマッピングします。したがって、本番環境では使用しないことを推奨します。ソースマップが有効になっている場合、Angularプロジェクトの元の状態を再現することで、可読性が向上し、ファイルの分析が容易になります。ただし、無効になっている場合でも、コンパイルされたJavaScriptファイルをセキュリティのパターンを検索して手動で分析することができます。
|
||||
|
||||
さらに、AngularプロジェクトのコンパイルされたJavaScriptファイルは、ブラウザの開発者ツール→ソース(またはデバッガとソース)→[id].main.jsで見つけることができます。有効なオプションに応じて、このファイルの最後に次の行が含まれている場合があります `//# sourceMappingURL=[id].main.js.map` または、**hidden**オプションが**true**に設定されている場合は含まれていない場合もあります。ただし、**scripts**のソースマップが無効になっている場合、テストはより複雑になり、ファイルを取得することはできません。さらに、`ng build --source-map`のようにプロジェクトビルド中にソースマップを有効にすることもできます。
|
||||
|
||||
# データバインディング
|
||||
|
||||
バインディングとは、コンポーネントとそれに対応するビュー間の通信プロセスを指します。これは、データをAngularフレームワークに送受信するために使用されます。データは、イベント、補間、プロパティ、または双方向バインディングメカニズムを介してさまざまな手段で渡すことができます。さらに、データは関連するコンポーネント(親子関係)やService機能を使用して、関連のない2つのコンポーネント間で共有することもできます。
|
||||
|
||||
データフローによってバインディングを分類することができます:
|
||||
|
||||
- データソースからビューターゲットへ(*補間*、*プロパティ*、*属性*、*クラス*、*スタイル*を含む);テンプレート内で`[]`または`{{}}`を使用して適用できます。
|
||||
- ビューターゲットからデータソースへ(*イベント*を含む);テンプレート内で`()`を使用して適用できます。
|
||||
- 双方向;テンプレート内で`[()]`を使用して適用できます。
|
||||
|
||||
バインディングは、プロパティ、イベント、属性、およびソースディレクティブの任意の公開メンバーに対して呼び出すことができます:
|
||||
|
||||
| タイプ | ターゲット | 例 |
|
||||
| ------ | ---------- | -- |
|
||||
| プロパティ | 要素プロパティ、コンポーネントプロパティ、ディレクティブプロパティ | <img [alt]="hero.name" [src]="heroImageUrl"> |
|
||||
| イベント | 要素イベント、コンポーネントイベント、ディレクティブイベント | <button type="button" (click)="onSave()">Save</button> |
|
||||
| 双方向 | イベントとプロパティ | <input [(ngModel)]="name"> |
|
||||
| 属性 | 属性(例外) | <button type="button" [attr.aria-label]="help">help</button> |
|
||||
| クラス | クラスプロパティ | <div [class.special]="isSpecial">Special</div> |
|
||||
| スタイル | スタイルプロパティ | <button type="button" [style.color]="isSpecial ? 'red' : 'green'"> |
|
||||
|
||||
# Angularセキュリティモデル
|
||||
|
||||
Angularの設計には、デフォルトですべてのデータのエンコードまたはサニタイズが含まれており、AngularプロジェクトでXSS脆弱性を発見して悪用することがますます困難になっています。データの処理には2つの異なるシナリオがあります:
|
||||
|
||||
1. 補間または`{{user_input}}`- コンテキストに応じたエンコードを実行し、ユーザーの入力をテキストとして解釈します。
|
||||
|
||||
```jsx
|
||||
//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"`- 提供されたセキュリティコンテキストに基づいてサニタイズが実行されます。
|
||||
|
||||
```jsx
|
||||
//app.component.ts
|
||||
test = "<script>alert(1)</script><h1>test</h1>";
|
||||
|
||||
//app.component.html
|
||||
<div [innerHtml]="test"></div>
|
||||
```
|
||||
|
||||
結果:`<div><h1>test</h1></div>`
|
||||
|
||||
`SecurityContext`には6つのタイプがあります:
|
||||
|
||||
- `None`;
|
||||
- `HTML`は、値をHTMLとして解釈する場合に使用されます;
|
||||
- `STYLE`は、CSSを`style`プロパティにバインディングする場合に使用されます;
|
||||
- `URL`は、`<a href>`などのURLプロパティに使用されます;
|
||||
- `SCRIPT`は、JavaScriptコードに使用されます;
|
||||
- `RESOURCE_URL`は、コードとしてロードおよび実行されるURLを表します。たとえば、`<script src>`内で使用されます。
|
||||
|
||||
# 脆弱性
|
||||
|
||||
## セキュリティトラストメソッドのバイパス
|
||||
|
||||
Angularでは、デフォルトのサニタイズプロセスをバイパスし、特定のコンテキストで値を安全に使用できることを示すためのメソッドのリストが導入されています。以下の5つの例に示すように:
|
||||
|
||||
1. `bypassSecurityTrustUrl`は、指定された値が安全なスタイルURLであることを示すために使用されます:
|
||||
|
||||
```jsx
|
||||
//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>
|
||||
```
|
||||
|
||||
2. `bypassSecurityTrustResourceUrl`は、指定された値が安全なリソースURLであることを示すために使用されます:
|
||||
|
||||
```jsx
|
||||
//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">
|
||||
```
|
||||
|
||||
3. `bypassSecurityTrustHtml`は、指定された値が安全なHTMLであることを示すために使用されます。この方法でDOMツリーに`script`要素を挿入しても、それらが含まれるJavaScriptコードを実行することはありません。
|
||||
|
||||
```jsx
|
||||
//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>
|
||||
```
|
||||
|
||||
4. `bypassSecurityTrustScript`は、指定された値が安全なJavaScriptであることを示すために使用され
|
||||
## HTMLインジェクション
|
||||
|
||||
この脆弱性は、ユーザーの入力が`innerHTML`、`outerHTML`、または`iframe`の`srcdoc`のいずれかのプロパティにバインドされた場合に発生します。これらの属性にバインドすると、HTMLがそのまま解釈されますが、入力は`SecurityContext.HTML`を使用してサニタイズされます。したがって、HTMLインジェクションは可能ですが、クロスサイトスクリプティング(XSS)はありません。
|
||||
|
||||
`innerHTML`の使用例:
|
||||
```jsx
|
||||
//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>
|
||||
```
|
||||
結果は `<div><h1>test</h1></div>` です。
|
||||
|
||||
## テンプレートインジェクション
|
||||
|
||||
### クライアントサイドレンダリング(CSR)
|
||||
|
||||
Angularはテンプレートを使用してページを動的に構築します。このアプローチでは、Angularが評価するために二重の中括弧(`{{}}`)で囲まれたテンプレート式を使用します。このようにすることで、フレームワークは追加の機能を提供します。たとえば、`{{1+1}}`というテンプレートは2と表示されます。
|
||||
|
||||
通常、Angularはテンプレート式と混同される可能性のあるユーザーの入力をエスケープします(たとえば、`< > ' " ```などの文字)。これは、ブラックリストに登録された文字を使用しないようにするために、JavaScriptの文字列オブジェクトを生成する関数を利用するなど、追加の手順が必要であることを意味します。ただし、これを実現するには、Angularのコンテキスト、プロパティ、および変数を考慮する必要があります。したがって、テンプレートインジェクション攻撃は次のように表示される場合があります:
|
||||
```jsx
|
||||
//app.component.ts
|
||||
const _userInput = '{{constructor.constructor(\'alert(1)\'()}}'
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: '<h1>title</h1>' + _userInput
|
||||
})
|
||||
```
|
||||
上記のように、`constructor`はオブジェクトの`constructor`プロパティのスコープを指します。これにより、Stringコンストラクタを呼び出して任意のコードを実行することができます。
|
||||
|
||||
### サーバーサイドレンダリング(SSR)
|
||||
|
||||
CSRとは異なり、Angular UniversalはテンプレートファイルのSSRを担当し、これらのファイルはユーザーに配信されます。ただし、この違いにもかかわらず、Angular UniversalはCSRで使用される同じサニタイズメカニズムを適用してSSRのセキュリティを強化します。SSRにおけるテンプレートインジェクションの脆弱性は、CSRと同じように検出することができます。なぜなら、使用されるテンプレート言語が同じだからです。
|
||||
|
||||
もちろん、PugやHandlebarsなどのサードパーティのテンプレートエンジンを使用する場合、新たなテンプレートインジェクションの脆弱性が発生する可能性もあります。
|
||||
|
||||
## XSS
|
||||
|
||||
### DOMインターフェース
|
||||
|
||||
前述のように、*Document*インターフェースを使用して直接DOMにアクセスすることができます。ユーザーの入力が事前に検証されていない場合、クロスサイトスクリプティング(XSS)の脆弱性が発生する可能性があります。
|
||||
|
||||
以下の例では、`document.write()`と`document.createElement()`メソッドを使用しました:
|
||||
```jsx
|
||||
//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のクラス
|
||||
|
||||
Angularでは、DOM要素を操作するために使用できるいくつかのクラスがあります: `ElementRef`、`Renderer2`、`Location`、`Document`です。最後の2つのクラスの詳細な説明は、**オープンリダイレクト**セクションで説明されています。最初の2つのクラスの主な違いは、`Renderer2` APIがDOM要素とコンポーネントコードの間に抽象化レイヤーを提供することであり、`ElementRef`は要素への参照を保持するだけです。したがって、Angularのドキュメントによれば、`ElementRef` APIは、DOMへの直接アクセスが必要な場合にのみ最後の手段として使用するべきです。
|
||||
|
||||
- `ElementRef`には、DOM要素を操作するために使用できる`nativeElement`というプロパティが含まれています。ただし、`nativeElement`の不適切な使用は、以下のようにXSSインジェクションの脆弱性を引き起こす可能性があります。
|
||||
|
||||
```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);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `Renderer2`は、ネイティブ要素への直接アクセスがサポートされていない場合でも安全に使用できるAPIを提供していますが、いくつかのセキュリティ上の欠陥があります。`Renderer2`を使用すると、`setAttribute()`メソッドを使用してHTML要素に属性を設定することができますが、これには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>
|
||||
```
|
||||
|
||||
- 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', '<img src=1 onerror=alert(1)>');
|
||||
}
|
||||
}
|
||||
|
||||
//app.component.html
|
||||
<a #a></a>
|
||||
<button (click)="setProperty()">Click me!</button>
|
||||
```
|
||||
|
||||
|
||||
私たちの調査では、XSSおよびCSSインジェクションに関連する他の`Renderer2`メソッド(`setStyle()`、`createComment()`、`setValue()`など)の動作も調べました。しかし、これらのメソッドには機能的な制限があるため、これらのメソッドに対する有効な攻撃ベクトルを見つけることはできませんでした。
|
||||
|
||||
### jQuery
|
||||
|
||||
jQueryは、AngularプロジェクトでHTML DOMオブジェクトの操作を補助するために使用できる高速で小さな機能豊富なJavaScriptライブラリです。ただし、このライブラリのメソッドはXSSの脆弱性を引き起こす可能性があることが知られています。このサブセクションでは、Angularプロジェクトでいくつかの脆弱なjQueryメソッドがどのように悪用されるかについて説明します。
|
||||
|
||||
- `html()`メソッドは、一致した要素セットの最初の要素のHTMLコンテンツを取得するか、すべての一致した要素のHTMLコンテンツを設定します。ただし、設計上、HTML文字列を受け入れる任意のjQueryコンストラクタまたはメソッドは、コードを実行する可能性があります。これは、`<script>`タグのインジェクションやコードを実行するHTML属性の使用によって発生する可能性があります。
|
||||
|
||||
```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>
|
||||
```
|
||||
|
||||
- `jQuery.parseHTML()`メソッドは、文字列をDOMノードのセットに変換するためにネイティブメソッドを使用し、それをドキュメントに挿入することができます。
|
||||
|
||||
```tsx
|
||||
jQuery.parseHTML(data [, context ] [, keepScripts ])
|
||||
```
|
||||
|
||||
前述のように、HTML文字列を受け入れるほとんどのjQuery APIは、HTMLに含まれるスクリプトを実行します。`jQuery.parseHTML()`メソッドは、`keepScripts`が明示的に`true`でない限り、解析されたHTML内のスクリプトを実行しません。ただし、ほとんどの環境では、`<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>
|
||||
```
|
||||
|
||||
## オープンリダイレクト
|
||||
|
||||
### DOMインターフェース
|
||||
|
||||
W3Cのドキュメントによると、`window.location`と`document.location`オブジェクトは、モダンなブラウザではエイリアスとして扱われます。そのため、いくつかのメソッドとプロパティの実装が類似しているため、`javascript://`スキーマのオープンリダイレクトとDOM XSSが発生する可能性があります。
|
||||
|
||||
- `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
|
||||
<button type="button" (click)="goToUrl()">Click me!</button>
|
||||
```
|
||||
|
||||
以下のシナリオに対して、悪用プロセスは同じです。
|
||||
|
||||
- `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()`)
|
||||
### Angular クラス
|
||||
|
||||
- Angularのドキュメントによると、Angularの`Document`はDOMのdocumentと同じであり、Angularでクライアントサイドの脆弱性を悪用するために一般的なベクターをDOMのdocumentに使用することが可能です。`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
|
||||
<button type="button" (click)="goToUrl()">Click me!</button>
|
||||
```
|
||||
|
||||
- 調査フェーズでは、Angularの`Location`クラスもオープンリダイレクトの脆弱性について調査しましたが、有効なベクターは見つかりませんでした。`Location`は、アプリケーションがブラウザの現在のURLとやり取りするために使用できるAngularのサービスです。このサービスには、与えられた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.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)
|
Loading…
Reference in a new issue