Angular
The Checklist
Checklist from here.
What is Angular
Angularは強力でオープンソースのフロントエンドフレームワークで、Googleによって維持されています。TypeScriptを使用してコードの可読性とデバッグを向上させます。強力なセキュリティメカニズムにより、AngularはXSSやオープンリダイレクトなどの一般的なクライアントサイドの脆弱性を防ぎます。また、サーバーサイドでも使用できるため、両方の視点からセキュリティの考慮が重要です。
Framework architecture
Angularの基本をよりよく理解するために、その基本的な概念を見ていきましょう。
一般的なAngularプロジェクトは通常次のようになります:
According to the documentation, every Angular application has at least one component, the root component (AppComponent
) that connects a component hierarchy with the DOM. Each component defines a class that contains application data and logic, and is associated with an HTML template that defines a view to be displayed in a target environment. The @Component()
decorator identifies the class immediately below it as a component, and provides the template and related component-specific metadata. The AppComponent
is defined in the app.component.ts
file.
Angular NgModules declare a compilation context for a set of components that is dedicated to an application domain, a workflow, or a closely related set of capabilities. Every Angular application has a root module, conventionally named AppModule
, which provides the bootstrap mechanism that launches the application. An application typically contains many functional modules. The AppModule
is defined in the app.module.ts
file.
The Angular Router
NgModule provides a service that lets you define a navigation path among the different application states and view hierarchies in your application. The RouterModule
is defined in the app-routing.module.ts
file.
For data or logic that isn't associated with a specific view, and that you want to share across components, you create a service class. A service class definition is immediately preceded by the @Injectable()
decorator. The decorator provides the metadata that allows other providers to be injected as dependencies into your class. Dependency injection (DI) lets you keep your component classes lean and efficient. They don't fetch data from the server, validate user input, or log directly to the console; they delegate such tasks to services.
Sourcemap configuration
Angular framework translates TypeScript files into JavaScript code by following tsconfig.json
options and then builds a project with angular.json
configuration. Looking at angular.json
file, we observed an option to enable or disable a sourcemap. According to the Angular documentation, the default configuration has a sourcemap file enabled for scripts and is not hidden by default:
ドキュメントによると、すべてのAngularアプリケーションには、コンポーネント階層をDOMに接続するルートコンポーネント(AppComponent
)が少なくとも1つあります。各コンポーネントは、アプリケーションデータとロジックを含むクラスを定義し、ターゲット環境に表示されるビューを定義するHTMLテンプレートに関連付けられています。@Component()
デコレーターは、その直下のクラスをコンポーネントとして識別し、テンプレートと関連するコンポーネント固有のメタデータを提供します。AppComponent
はapp.component.ts
ファイルで定義されています。
Angular NgModulesは、アプリケーションドメイン、ワークフロー、または密接に関連する機能セットに専念するコンポーネントのセットのコンパイルコンテキストを宣言します。すべてのAngularアプリケーションには、通常AppModule
と呼ばれるルートモジュールがあり、アプリケーションを起動するブートストラップメカニズムを提供します。アプリケーションには通常、多くの機能モジュールが含まれています。AppModule
はapp.module.ts
ファイルで定義されています。
Angular Router
NgModuleは、アプリケーション内の異なるアプリケーション状態とビュー階層の間にナビゲーションパスを定義できるサービスを提供します。RouterModule
はapp-routing.module.ts
ファイルで定義されています。
特定のビューに関連付けられていないデータやロジックで、コンポーネント間で共有したい場合は、サービスクラスを作成します。サービスクラスの定義は、@Injectable()
デコレーターによって直前に示されます。このデコレーターは、他のプロバイダーがクラスに依存関係として注入されることを可能にするメタデータを提供します。依存性注入(DI)により、コンポーネントクラスをスリムで効率的に保つことができます。彼らはサーバーからデータを取得したり、ユーザー入力を検証したり、コンソールに直接ログを記録したりしません。これらのタスクはサービスに委任されます。
ソースマップの設定
Angularフレームワークは、tsconfig.json
オプションに従ってTypeScriptファイルをJavaScriptコードに変換し、その後angular.json
構成でプロジェクトをビルドします。angular.json
ファイルを見てみると、ソースマップを有効または無効にするオプションがあることがわかりました。Angularのドキュメントによると、デフォルトの構成では、スクリプト用のソースマップファイルが有効になっており、デフォルトでは隠されていません。
一般的に、sourcemapファイルはデバッグ目的で使用され、生成されたファイルを元のファイルにマッピングします。したがって、プロダクション環境での使用は推奨されません。sourcemapsが有効になっている場合、Angularプロジェクトの元の状態を再現することで、可読性が向上し、ファイル分析に役立ちます。しかし、無効にされている場合、レビュアーはセキュリティ対策パターンを検索することで、コンパイルされたJavaScriptファイルを手動で分析することができます。
さらに、AngularプロジェクトのコンパイルされたJavaScriptファイルは、ブラウザの開発者ツール → ソース(またはデバッガーとソース) → [id].main.jsに見つけることができます。有効なオプションに応じて、このファイルの最後には//# sourceMappingURL=[id].main.js.map
という行が含まれている場合がありますが、hiddenオプションがtrueに設定されている場合は含まれません。それにもかかわらず、scriptsのsourcemapが無効になっている場合、テストはより複雑になり、ファイルを取得することはできません。さらに、プロジェクトビルド中にsng build --source-map
のようにsourcemapを有効にすることができます。
データバインディング
バインディングは、コンポーネントとその対応するビュー間の通信プロセスを指します。これは、Angularフレームワークにデータを転送するために利用されます。データは、イベント、補間、プロパティ、または双方向バインディングメカニズムを通じて渡すことができます。さらに、データは関連するコンポーネント(親子関係)間や、サービス機能を使用して無関係な2つのコンポーネント間でも共有できます。
バインディングはデータフローによって分類できます:
データソースからビューターゲットへ(interpolation、properties、attributes、classes、_styles_を含む);テンプレートで
[]
または{{}}
を使用して適用できます;ビューターゲットからデータソースへ(_events_を含む);テンプレートで
()
を使用して適用できます;双方向;テンプレートで
[()]
を使用して適用できます。
バインディングは、プロパティ、イベント、属性、およびソースディレクティブの任意のパブリックメンバーに対して呼び出すことができます:
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の設計には、すべてのデータのエンコーディングまたはサニタイズがデフォルトで含まれており、AngularプロジェクトにおけるXSS脆弱性の発見と悪用がますます困難になっています。データ処理には2つの異なるシナリオがあります:
補間または
{{user_input}}
- コンテキストに応じたエンコーディングを実行し、ユーザー入力をテキストとして解釈します;
結果: <script>alert(1)</script><h1>test</h1>
2. プロパティ、属性、クラス、スタイルへのバインディングまたは[attribute]="user_input"
- 提供されたセキュリティコンテキストに基づいてサニタイズを実行します。
結果: <div><h1>test</h1></div>
SecurityContext
には6種類があります:
None
;HTML
は、値をHTMLとして解釈する際に使用されます;STYLE
は、style
プロパティにCSSをバインドする際に使用されます;URL
は、<a href>
のようなURLプロパティに使用されます;SCRIPT
は、JavaScriptコードに使用されます;RESOURCE_URL
は、コードとして読み込まれ実行されるURL、例えば<script src>
で使用されます。
脆弱性
セキュリティトラストメソッドのバイパス
Angularは、デフォルトのサニタイズプロセスをバイパスし、特定のコンテキストで値が安全に使用できることを示すためのメソッドのリストを導入しています。以下の5つの例のように:
bypassSecurityTrustUrl
は、指定された値が安全なスタイルURLであることを示すために使用されます:
bypassSecurityTrustResourceUrl
は、指定された値が安全なリソースURLであることを示すために使用されます:
bypassSecurityTrustHtml
は、指定された値が安全なHTMLであることを示すために使用されます。注意すべきは、この方法でDOMツリーにscript
要素を挿入しても、含まれるJavaScriptコードが実行されないことです。
bypassSecurityTrustScript
は、指定された値が安全なJavaScriptであることを示すために使用されます。しかし、このメソッドを使用してテンプレート内でJSコードを実行できなかったため、その動作は予測不可能であることがわかりました。
bypassSecurityTrustStyle
は、指定された値が安全なCSSであることを示すために使用されます。以下の例はCSSインジェクションを示しています:
Angularは、ビューに表示する前にデータをサニタイズするためのsanitize
メソッドを提供しています。このメソッドは、提供されたセキュリティコンテキストを使用し、入力を適切にクリーンアップします。ただし、特定のデータとコンテキストに対して正しいセキュリティコンテキストを使用することが重要です。たとえば、HTMLコンテンツにSecurityContext.URL
を適用すると、危険なHTML値に対する保護が提供されません。このようなシナリオでは、セキュリティコンテキストの誤用がXSS脆弱性を引き起こす可能性があります。
HTMLインジェクション
この脆弱性は、ユーザー入力がinnerHTML
、outerHTML
、またはiframe
srcdoc
のいずれかの3つのプロパティにバインドされるときに発生します。これらの属性にバインドすると、HTMLがそのまま解釈され、入力はSecurityContext.HTML
を使用してサニタイズされます。したがって、HTMLインジェクションは可能ですが、クロスサイトスクリプティング(XSS)は発生しません。
innerHTML
を使用した例:
結果は <div><h1>test</h1></div>
です。
テンプレートインジェクション
クライアントサイドレンダリング (CSR)
Angularは、ページを動的に構築するためにテンプレートを活用します。このアプローチは、Angularが評価するためのテンプレート式を二重波括弧({{}}
)で囲むことを含みます。このようにして、フレームワークは追加の機能を提供します。例えば、{{1+1}}
というテンプレートは2として表示されます。
通常、Angularはテンプレート式と混同される可能性のあるユーザー入力(例:`< > ' " `などの文字)をエスケープします。これは、ブラックリストに載っている文字を使用しないためにJavaScript文字列オブジェクトを生成する関数を利用するなど、この制限を回避するために追加の手順が必要であることを意味します。しかし、これを達成するためには、Angularのコンテキスト、そのプロパティ、および変数を考慮する必要があります。したがって、テンプレートインジェクション攻撃は次のように見えるかもしれません:
上記のように、constructor
はObject constructor
プロパティのスコープを指し、Stringコンストラクタを呼び出して任意のコードを実行することを可能にします。
サーバーサイドレンダリング (SSR)
CSRがブラウザのDOMで発生するのに対し、Angular UniversalはテンプレートファイルのSSRを担当します。これらのファイルはユーザーに配信されます。この区別にもかかわらず、Angular UniversalはSSRのセキュリティを強化するためにCSRで使用されるのと同じサニタイズメカニズムを適用します。SSRにおけるテンプレートインジェクションの脆弱性は、使用されるテンプレート言語が同じであるため、CSRと同じ方法で検出できます。
もちろん、PugやHandlebarsなどのサードパーティのテンプレートエンジンを使用する際に、新しいテンプレートインジェクションの脆弱性が導入される可能性もあります。
XSS
DOMインターフェース
前述のように、_Document_インターフェースを使用してDOMに直接アクセスできます。ユーザー入力が事前に検証されていない場合、クロスサイトスクリプティング (XSS) の脆弱性につながる可能性があります。
以下の例では、document.write()
とdocument.createElement()
メソッドを使用しました:
Angularクラス
AngularでDOM要素を操作するために使用できるクラスがいくつかあります:ElementRef
、Renderer2
、Location
、およびDocument
。最後の2つのクラスについての詳細な説明は、オープンリダイレクトセクションに記載されています。最初の2つの主な違いは、Renderer2
APIがDOM要素とコンポーネントコードの間に抽象化の層を提供するのに対し、ElementRef
は単に要素への参照を保持することです。したがって、Angularのドキュメントによれば、ElementRef
APIはDOMへの直接アクセスが必要な場合の最後の手段としてのみ使用されるべきです。
ElementRef
には、DOM要素を操作するために使用できるnativeElement
プロパティが含まれています。しかし、nativeElement
の不適切な使用は、以下に示すようにXSSインジェクションの脆弱性を引き起こす可能性があります:
Renderer2
がネイティブ要素への直接アクセスがサポートされていない場合でも安全に使用できるAPIを提供するにもかかわらず、いくつかのセキュリティの欠陥があります。Renderer2
を使用すると、setAttribute()
メソッドを使用してHTML要素に属性を設定できますが、これはXSS防止メカニズムを持っていません。
DOM要素のプロパティを設定するには、
Renderer2.setProperty()
メソッドを使用してXSS攻撃を引き起こすことができます:
私たちの研究中に、setStyle()
、createComment()
、およびsetValue()
などの他のRenderer2
メソッドのXSSおよびCSSインジェクションに関する動作も調査しました。しかし、これらのメソッドの機能的制限のため、有効な攻撃ベクターを見つけることはできませんでした。
jQuery
jQueryは、AngularプロジェクトでHTML DOMオブジェクトを操作するのに役立つ、高速で小型、機能豊富なJavaScriptライブラリです。しかし、知られているように、このライブラリのメソッドはXSS脆弱性を引き起こすために悪用される可能性があります。脆弱なjQueryメソッドがAngularプロジェクトでどのように悪用されるかを議論するために、このサブセクションを追加しました。
html()
メソッドは、一致した要素のセットの最初の要素のHTMLコンテンツを取得するか、すべての一致した要素のHTMLコンテンツを設定します。しかし、設計上、HTML文字列を受け入れるjQueryのコンストラクタやメソッドは、コードを実行する可能性があります。これは、<script>
タグの注入や、コードを実行するHTML属性の使用によって発生する可能性があります。
jQuery.parseHTML()
メソッドは、ネイティブメソッドを使用して文字列をDOMノードのセットに変換し、それをドキュメントに挿入できます。
前述のように、HTML文字列を受け入れるほとんどのjQuery APIは、HTMLに含まれるスクリプトを実行します。jQuery.parseHTML()
メソッドは、keepScripts
が明示的にtrue
でない限り、解析されたHTML内のスクリプトを実行しません。しかし、ほとんどの環境では、<img onerror>
属性を介して間接的にスクリプトを実行することが可能です。
オープンリダイレクト
DOMインターフェース
W3Cのドキュメントによると、window.location
およびdocument.location
オブジェクトは、現代のブラウザではエイリアスとして扱われます。これが理由で、いくつかのメソッドやプロパティの実装が似ており、以下に示すようにjavascript://
スキーマ攻撃によるオープンリダイレクトやDOM XSSを引き起こす可能性があります。
window.location.href
(およびdocument.location.href
)
現在のDOMロケーションオブジェクトを取得するための標準的な方法は、window.location
を使用することです。また、ブラウザを新しいページにリダイレクトするためにも使用できます。その結果、このオブジェクトを制御することで、オープンリダイレクトの脆弱性を悪用することができます。
以下のシナリオに対する悪用プロセスは同じです。
window.location.assign()
(およびdocument.location.assign()
)
このメソッドは、指定されたURLのドキュメントを読み込み、表示するためにウィンドウを引き起こします。このメソッドを制御できる場合、オープンリダイレクト攻撃のためのシンクになる可能性があります。
window.location.replace()
(およびdocument.location.replace()
)
このメソッドは、現在のリソースを提供されたURLのものと置き換えます。
assign()
メソッドとの違いは、window.location.replace()
を使用した後、現在のページがセッション履歴に保存されないことです。しかし、このメソッドを制御できる場合、オープンリダイレクトの脆弱性を悪用することも可能です。
window.open()
window.open()
メソッドは、URLを受け取り、それが識別するリソースを新しいタブまたはウィンドウに読み込みます。このメソッドを制御することで、XSSまたはオープンリダイレクトの脆弱性を引き起こす機会もあります。
Angularクラス
Angularのドキュメントによれば、Angularの
Document
はDOMドキュメントと同じであり、Angular内のクライアントサイドの脆弱性を悪用するためにDOMドキュメントの一般的なベクターを使用することが可能です。Document.location
プロパティとメソッドは、以下の例に示すように、成功したオープンリダイレクト攻撃のシンクになる可能性があります:
研究段階では、オープンリダイレクトの脆弱性に対してAngularの
Location
クラスもレビューしましたが、有効なベクターは見つかりませんでした。Location
は、アプリケーションがブラウザの現在のURLと対話するために使用できるAngularサービスです。このサービスには、与えられたURLを操作するためのいくつかのメソッドがあります -go()
、replaceState()
、およびprepareExternalUrl()
。しかし、外部ドメインへのリダイレクトには使用できません。例えば:
結果:http://localhost:4200/http://google.com/about
Angularの
Router
クラスは主に同じドメイン内のナビゲーションに使用され、アプリケーションに追加の脆弱性を導入しません:
結果:http://localhost:4200/https:
以下のメソッドもドメインの範囲内でナビゲートします:
参考文献
Last updated