Angularのセキュリティベストプラクティス
Natalia Venditto
2020年8月10日
0 分で読めます以前、AngularJSのセキュリティ基礎チートシートをご紹介しました。今回は、最新のAngularにおけるセキュリティのベストプラクティスを詳しく見ていきます。Angularセキュリティベストプラクティスのチートシートはこちらからダウンロードできます。
Angularのセキュリティベストプラクティス6選
「Angularらしい」方法でXSSを防ぐ
innerHTMLは慎重に使う
ユーザー入力を連結してテンプレートを生成しない
HTML要素の操作にネイティブDOM APIを使わない
サーバーサイドテンプレートでテンプレートエンジンを使わない
Angularプロジェクトをスキャンして、セキュリティ脆弱性を引き起こすコンポーネントを見つける
1. 「Angularらしい」方法でXSSを防ぐ
Angularのセキュリティベストプラクティス #1:補間({{ }})を使って、危険な可能性のある文字を安全にエンコードし、テンプレート式内の信頼できないHTMLまたはCSS式をエスケープします。
AngularはReactやVue.jsと同様に、ブラウザーで文字列補間を処理する際、デフォルトで安全性を確保する設計になっています。デフォルトでは、すべてのデータを安全でない、信頼できないものとして扱います。そのため、これらをはじめとする最新のビューライブラリでは、HTMLコンテキスト内のテキストに対して、デフォルトで出力エンコードを行うことがベストプラクティスとなっています。
以前のブログ記事AngularJSのセキュリティベストプラクティスで詳しく説明したように、組み込みの波括弧による文字列補間を使う「Angularらしい」方法に従うことを強くおすすめします。悪意のあるユーザー入力をエスケープすることで、Webアプリケーションを危険にさらしたり、クロスサイトスクリプティング(XSS)の脆弱性につながったりするリスクを防げます。
2. innerHTMLは慎重に使う
Angularのセキュリティベストプラクティス #2:コンポーネントにHTMLを動的に追加する必要がある場合は、その生成を [innerHTML]にバインドします。これにより、データはコンテキスト内でHTMLとして解釈され、サニタイズされます。安全でないタグがすべて取り除かれるため、悪意のあるクロスサイトスクリプティングコードの実行を防げます。なお、 サニタイズ と エンコードは同じではありません。
サニタイズと出力エンコードの違いとは?
出力エンコードでは、文字列がテキスト表現に置き換えられ、特定のHTMLタグに対応付けられることがあります。たとえば、scriptのような入力が解析されると、Angularは特殊な山括弧をエンコードして、そのテキストを表示できます。これは、セキュリティのベストプラクティスを実装する多くのライブラリやフレームワークで標準的に使われる方法です。そのために、HTMLエンティティエンコードと呼ばれる変換を行い、次のテキストをDOMに書き込みます:script。その後、ブラウザーがコンテキストを解釈し、scriptタグを出力します。
出力エンコードとは異なり、サニタイズやフィルタリングでは、安全でない文字を積極的に検出して取り除いてからDOMに書き込みます。
出力エンコードとサニタイズを適切に行うには、コンテキストが重要な判断要素となります。コンテキストによって、適切な処理方法が変わるためです。
セキュリティコンテキストについて詳しく知るには、Angularのドキュメントを参照してください。そこでは次のように説明されています。
Angularでは、次のセキュリティコンテキストが定義されています。
* HTML:innerHtmlへのバインドなど、値をHTMLとして解釈する場合に使用します。* Style:CSSをstyleプロパティにバインドする場合に使用します。* URL:などのURLプロパティに使用します。* リソースURL:コードとして読み込まれ実行されるURLです。たとえば、ではこのコンテキストが使われます。
URLは特別な扱いとなり、フィルタリングされない点に注意してください。
3. ユーザー入力を連結してテンプレートを生成しない
Angularのセキュリティベストプラクティス #3:ユーザーが入力した可能性のある値を文字列としてテンプレートに連結しないでください。
Angularアプリケーションで文字列補間や推奨されているコンポーネント構成を適切に使わず、テンプレートを連結する必要が生じるケースは、あったとしてもごくわずかです。コードベースでこのような悪い慣行を見つけた場合は、入力値を可能な限りサニタイズするか、リファクタリングしてください。
次の例のようなコードに注意し、使用を避けてください。

Angularのセキュリティベストプラクティス:ユーザー入力を連結してテンプレートを生成しない
20行目の一般的でない文字列からテンプレートへの連結に特に注意してください。potentialUserInputの値は、出所が不明または信頼できない悪意のある式である可能性があります。これは避けるべき悪い慣行の一例です。
以下は、Angularのプレイグラウンドで試せる、ユーザー入力をテンプレートに連結すると安全に処理されないことを示す、より詳しい例です。

Angularセキュリティの実践例:ユーザー入力を連結してテンプレートを生成しない
この点について、Angularセキュリティガイドでは次のように推奨しています。
「ユーザー入力とテンプレートを連結してテンプレートのソースコードを生成しないでください。こうした脆弱性を防ぐには、オフラインテンプレートコンパイラー(テンプレートインジェクションとも呼ばれます)を使用してください。」
- Angularセキュリティガイド
Angularでは、Ahead of Time(AOT)コンパイラーを使用してテンプレートをオフラインでコンパイルすることを推奨しています。これにより、さまざまなテンプレートインジェクションの脆弱性を完全に回避できます。
Angularの最新バージョン(v9以降)では、Ivyでコンパイルする場合、Ahead of Timeコンパイルがデフォルトで有効になっており、テンプレートインジェクションを防ぎます。
4. HTML要素の操作にネイティブDOM APIを使わない
Angularのセキュリティベストプラクティス #4:ページ上のHTML要素の操作にネイティブDOM APIを使わないでください。
DOMを直接操作するのではなく、Angularのテンプレート機能や独自のAPIを使ってDOMを操作してください。一般的な指針として、次の方法は避けましょう。
node.appendChild();ページの操作に
documentオブジェクトのメソッドを使うjQuery APIを使う
Angularには、避けるよう推奨しているものと同種のDOM直接操作を可能にするネイティブAPIもあります。たとえば、ElementRef APIです。ElementRefを使って直接DOMノードにアクセスし、操作を行うと、セキュリティ上の問題が生じる可能性があります。
このような操作や、Angular API以外を使った操作は、セキュリティ脆弱性につながる可能性があります。
5. サーバーサイドテンプレートでテンプレートエンジンを使わない
Angularのセキュリティベストプラクティス #5:Angularのサーバーサイドレンダリングアプリケーションでテンプレートの作成やデータの追加に、サードパーティ製のテンプレートエンジンを使わないでください。
Node.jsでWebアプリケーションを構築したことがあれば、EJS、Pug、Handlebarsなどのテンプレートエンジンや、その代替ツールを使ったことがあるでしょう。これらはビュー層のサーバーサイドレンダリングテンプレートを管理するために使われ、パーシャルやレイアウトの合成など、ビューを動的に生成するためのさまざまな機能を備えています。
しかし、Angularのサーバーサイドレンダリングアプリケーションでこうしたテンプレートエンジンを使うと、テンプレートに悪意のあるコードが挿入される可能性があります。注入されるデータはAngular APIの範囲外にあるためサニタイズできず、テンプレート文字列を連結する場合と同じリスクが生じます。
6. Angularプロジェクトをスキャンして、セキュリティ脆弱性を引き起こすコンポーネントを見つける
Angularプロジェクトのオープンソース依存関係とAngularコンポーネントを常にスキャンし、セキュリティ脆弱性を確認しましょう。SnykのプラットフォームまたはCLIを無料で使って、セキュリティ脆弱性を 検出、修正し、継続的に監視できます。
Angularやそのエコシステムに含まれるモジュールやコンポーネントなど、サードパーティライブラリを使う際は、次の点に注意しましょう。Angularコアライブラリに影響するセキュリティ脆弱性と、プロジェクトにインポートして使用しているサードパーティ製Angularモジュールのセキュリティ脆弱性です。
既知の脆弱性があるコンポーネントの使用は、OWASP Top 10で記載されているWebセキュリティリスクです。注意が必要です。実際、下の図は既知のセキュリティ脆弱性があるAngularモジュールの一覧です。たとえば、npm installやnpm auditの実行時に検出されるものです。JavaScriptフレームワークセキュリティレポートから引用したこの図が示すように、年間何百万回もダウンロードされているにもかかわらず、現時点でセキュリティ修正がないものもあります。

Angular Webアプリケーションを保護する
npm auditを使っているなら、それは素晴らしい第一歩です。すでに適切な対応ができています。
ただし、npmのaudit機能を使っていても、対処すべきセキュリティ上の懸念は残っています。
現時点でプロジェクト内のすべてのセキュリティ脆弱性を解消できたとしても、Angularモジュールに新たな脆弱性が見つかったらどうなるでしょうか。VercelやNetlifyなどにデプロイしたAngularアプリケーションへの影響に気づけるでしょうか。
もう1つの懸念は、
npm auditが公式なCVEがある既知の脆弱性のみを追跡することです。一方、[SnykはAngular関連モジュールの23件以上のセキュリティ脆弱性を追跡しています](https://snyk.io/blog/angular-vs-react-security-bakeoff-2019/)が、npm auditではこれらが報告されません。
Snykなら、こうした2つの懸念を解消できます。しかも無料です ;-)
利用を始めるには?
無料のSnykアカウントを作成し、GitHubまたはBitbucketのフロントエンドプロジェクトを接続しましょう。Snykが自動的に問題を検出し、修正用のプルリクエストを作成します。
Capture the Flagを始めよう
オンデマンドのバーチャル入門ワークショップを見て、Capture the Flagの課題の解き方を学びましょう。
Angularのセキュリティ問題をすぐに見つけるには、Snyk CLIを使う方法もあります。

出典:AngularとReact:セキュリティ対決 2019
Snykは、修正済みバージョンにアップグレードするための、具体的な修復アドバイスを提供します。
Angular向けのセキュリティスキャナーをお探しなら、Snykをぜひお試しください。オープンソース依存関係を追跡し、脆弱性の通知を受け取り、発見された脆弱性を修正できます。
あわせて読みたい記事:
AngularJSを保守または積極的に開発している方には、AngularJSのセキュリティ基礎ベストプラクティス10選がおすすめです。
セキュリティ態勢の観点から、AngularとReactはどう違うのでしょうか。詳しくまとめたJavaScriptフレームワークセキュリティレポートを公開しています。
Angularは安全ですか?
新しいAngularフレームワーク(Angular 2以降)は、デフォルトで安全なフレームワークと見なされており、既知のセキュリティ脆弱性はありません。一方、前身のAngularJSには、2020年6月時点で25件を超える公開済みのセキュリティ脆弱性があります。Angularのセキュリティベストプラクティスに従い、Angular、Reactなどのプロジェクトで使われるnpmモジュールのエコシステムのセキュリティを詳しく解説した、SnykのJavaScriptフレームワークセキュリティレポートもご覧ください。
Angularアプリケーションを安全にするには?
Angularアプリケーションを安全にするための基本的なガイドラインを紹介します。
1. 開発者として「Angularらしい」方法とベストプラクティスに従い、XSSからアプリケーションを保護しましょう。たとえば、innerHTMLを使わない、ユーザー入力を連結してテンプレートを生成しない、HTML要素の操作にネイティブDOM APIを使わない、といった対策です。
2. Angularプロジェクトをスキャンし、セキュリティ脆弱性を引き起こすコンポーネントを見つけましょう。Angular独自のセキュリティ対策に従っていても、他のモジュールの開発者が従っているとは限りません。深刻な問題にさらされる可能性があります。スキャンだけでなく、潜在的な新たな問題の修正と監視も行いましょう。Snykなら簡単に実現できます。プロジェクトに簡単に接続できる無料ツールです。詳しくはAngularのセキュリティベストプラクティスをご覧ください。
AngularとReactでは、どちらがより安全ですか?
Angularプロジェクト(Angular 2以降)には、現在公表されているセキュリティ脆弱性はありません。Reactには影響を及ぼすセキュリティ脆弱性が2件ありますが、いずれも2017年のもので、すでにそれより新しいバージョンをお使いでしょう。Angularの前身であるAngularJSには、25件を超えるセキュリティ脆弱性があります。まだ開発や保守を続けている場合は、無料で利用できる開発者ファーストのセキュリティツール、Snykなどでプロジェクトを必ずスキャンしてください。このテーマについては、AngularとReactのエコシステムのセキュリティ状況を調査したJavaScriptフレームワークのセキュリティレポートをご覧ください。
Angularでは入力値がサニタイズされますか?
Angularではデフォルトで、XSSにつながる可能性のある危険なテキストがすべて出力時にエンコードされます。安全な補間に二重中括弧({{}})を使うなど、Angularが推奨する安全なコーディングを実践していることが前提です。ただし、AngularのinnerHTMLバインディングを使用した場合も、Angularは危険なコンテンツをサニタイズして保護しようとします。それでも、ユーザー入力を追加する方法としては、最後の手段にとどめるべきです。
CTFを始めよう
オンデマンドのバーチャル入門ワークショップを視聴して、CTFの課題の解き方を学びましょう。



