この AngularJSセキュリティの ベストプラクティス・チートシートでは、 AngularJSに 焦点を 当て、 安全な コーディングを 実現する ための ヒントと ガイドラインを 紹介します。 つまり、 Web開発者向けに AngularJSセキュリティの 基礎を まとめた チートシートです。
AngularJSセキュリティの 基礎を ダウンロード
この ブログ記事では、 次の AngularJSセキュリティの ベストプラクティス10選 を 取り上げます。
「Angular流」の 方法で XSSから 保護する
Angular DOM関連の 入力インジェクションを 避ける
信頼できない ソースから Angularテンプレートを 動的に 読み込まない
AngularJSの オープンリダイレクト脆弱性
サーバーサイドAngularコードインジェクション
DOM 操作に Angularの jQuery互換API .elementを 使わない
Angular用セキュリティリンターを 使う
Angularの サードパーティーコンポーネントの 脆弱性を スキャンして 修正する
Angularアプリケーションの 組み込みCSRF対策
Angularに 組み込まれた CSPとの 互換性
AngularJSの セキュリティの ベストプラクティスが 重要なのは なぜでしょうか?
以前 実施した JavaScriptフレームワークの セキュリティ に 関する 調査に よると、 Angular v1.xは Angularの 全バージョンの ダウンロード数の 約30%を 占め、 201 9年7月には 200万件を わずかに 超える ダウンロードが ありました。
出典: https://snyk.io/blog/javascript-frameworks-security-report-2019/
AngularはAngularJSより優れているのでしょうか? Angularは AngularJSの 後 継バージョンです。 Angularの 中核コンポーネントでは、 報告された セキュリティ脆弱性が 見つかっていない 点に 注目してください。 一方、 AngularJSでは、 バージョン1.xの すべての リリースブランチを 通じて 23件の 脆弱性 が 追跡されています。
どのバージョンのAngularJSを使うべきでしょうか? 常に AngularJSの 最新バージョンを 選びましょう。 この 記事の 執筆時点では AngularJS 1.7が 最新です。 最新バージョンには セキュリティ修正が 反映されており、 202 1年6月30日まで サポートされる 予定です。
AngularJSの セキュリティに 関する 広範な 調査と 有益な 情報を 以前 共有してくださった Lewis Arden に 感謝します。 OWASP Londonで AngularJSの セキュリティに ついて 講演した 内容は こちら を ご覧ください。
AngularJSの GitHub / Bitbucketプロジェクトの セキュリティ脆弱性を テストする
1. 「Angular流」の方法でXSSから保護する AngularJSは デフォルトで、 DOMに 追加される あらゆる データ値に 対し、 コンテキストを 考慮した 出力エンコードと 入力サニタイズを 自動的に 適用します。 「Angular流」の 方法に 従っていれば、 この 保護機能を 利用できます。
いくつか 例を 見てみましょう。
Angularのng-bindを使う Angularの ng-bindディレクティブを 使うと、 コントローラーなどの Angularコードで 設定した 値を、 HTML要素の 値に バインドできます。
次の view.htmlは Angularテンプレートです。 ng-bindを 使って Angularコード内の 式を 展開し、 その 値を div HTML要素に 表示します。
この ビューに 値を 渡すコントローラーは AboutControllerです。
ご覧の とおり、 signatureの 値に HTML要素を 挿入し、 ブラウザーの window alertメッセージを 表示させようとする 試みを シミュレートしています。 しかし 画面に 表示される 際、 Angularは <などの 文字を HTMLエンティティに エンコードします。 その ため、 実際の HTML要素と して DOMに 挿入されるのではなく、 テキストと して 出力されます。
Angularの二重中括弧を使う HTML要素の 値に データを バインドする もう 一つの 方法は、 Angularの 規約である 二重中括弧を 使う ことです。 ngBindディレクティブと 中括弧表記は 同じ 機能ですが、 UXに 関して わずかな 違いが あります。
中括弧を 使った ときに Angularが 悪意ある データを どのように エンコードするか、 まず ビューに description値を 追加する 例で 見てみましょう。
次に、 クロスサイトスクリプティング攻撃 を ページに 挿入しようとする 悪意ある 値を 渡す、 対応する コントローラーを 示します。
「Angular流」の 方法に 従っている ため、 中括弧と ngBindディレクティブの 両方で 悪意の ある 可能性が ある ユーザー入力を 扱う とき、 Angularが クロスサイトスクリプティング攻撃への 対策と して 出力エンコードを 適用する ことが わかります。
要点: Angularの デフォルトの 保護機能を 活用して、 クロスサイトスクリプティング (XSS) 脆弱性を 軽減しましょう。 ngBindディレクティブや {{ data }}のような 中括弧を 使い、 「Angular流」に データを 展開すれば、 Angularが デフォルトで 出力エンコードと サニタイズを 適用します。
2. Angular DOM関連の入力インジェクションを避ける Angularの安全でないHTMLバインディングを悪用する AngularJS 1.2以前などの 旧バージョンには ng-bind-html-unsafeディレクティブが あり、 HTMLデータを DOMに 挿入して 新しい 要素を 作成できました。 この 機能を 使い、 入力データから 直接 DOM要素を 作成したうえで、 リンクなど 特定の 文字列を 削除する 方法も ありました。
このような アプローチで データを ブラックリスト化する 方法は、 時間とともに 新たな 攻撃経路や 手法が 見つかり、 ブラックリストの 保守が 必要に なる ため、 間違いやすく、 常に 安全とは 限りません。
ng-bind-html-unsafeが HTML要素を DOMに 挿入する 例を 見てみましょう。
Angularテンプレート:
ビューに 対応する Angularコントローラー:
レンダリングされた HTMLビューには 「Contact me」が 実際の リンクと して 表示され、 クリックすると alertが 実行されます。
AngularのStrict Contextual Escapingを悪用する AngularJS 1.2では ng-bind-html-unsafeディレクティブが 非推奨と なり、 代わりに Strict Contextual Escaping (SCE)が 導入されました。 SCEは、 特定の HTML要素の データではなく、 コンテキストに 基づいて データを エスケープし、 サニタイズします。
ただし、 エンコードを 回避して、 提供された データを 安全な ものとして 扱える 抜け道も 存在します。 Angularの $sce.trustAsHtml()や $sce.trustAs(type, value)メソッドを 使うと、 こうした 操作が 可能に なります。
さらに、 $sceProvider.enabled(false)を 使うと、 Strict Contextual Escapingを 全体的に 無効にし、 すべての サニタイズを 無視して 入力を 信頼できます。 これも 避けるべき 悪い プラクティスです。 本当に やむを 得ない 理由が ある 場合に 限って 使い、 他の 対策や 防御も 必ず 講じる ことを おすすめします。
ユーザーが リンクを 作成できるように する 一方で、 クロスサイトスクリプティング脆弱性を 引き起こす 例を 見てみましょう。 Angularテンプレートは 次の とおりです。
Angularコントローラー:
stripDangerousHTMLと いう Angularフィルターを 作成する ことで、 開発者は 悪意ある JavaScriptコードが href属性に 入り込まないようにしています。 メールアドレスだけが 使われるよう、 サニタイズする 想定です。
ユーザーが 入力した emailAddressの 値が 'javascript:alert(1)'なら、 正規表現に 基づく パターンマッチングは うまく 機能します。 しかし、 ユーザー入力が jav ascript:al ert(1);の 場合、 十分に 機能しません。 この 入力は パターンマッチングを 回避し、 有効な JavaScript文と して 扱われる ため、 XSSを 引き起こします。
要点: 脆弱性を 引き起こす 可能性が ある ため、 Angular DOM関連の 入力インジェクションは 避けましょう。
3. 信頼できないソースからAngularテンプレートを動的に読み込まない Angularコードでは、 常に Angularテンプレートを 使用します。 HTMLテンプレートは 次のような ものです。
通常、 Angularテンプレートは、 ビルド時に Angularアプリケーションへ 組み込まれる ファイルで 構成します。 一方、 実行時に クライアント側から リクエストを 送信して テンプレートを ダウンロードし、 動的に 評価する ことで、 HTMLテンプレートを 遅延読み込みする こともできます。
しかし、 Webアプリケーションの 制御や 信頼の 及ばない ドメインから テンプレートを 安全でない 方法で 読み込むリスクが 生じます。 また、 中間者攻撃 を 軽減する ため、 最新バージョンの TLSなど、 安全な プロトコルを 使って テンプレートに アクセスする 必要が あります。
Angularテンプレートを ネットワーク経由で 動的に 読み込む 例:
Angularでは テンプレートリソースを 制御できます。 公式ドキュメントには 次のように 説明されています。
$sceDelegateProviderを 使うと、 AngularJSテンプレートや その 他の スクリプト実行URL ($sce.RESOURCE_URLコンテキストを 使用する すべての 場所)の 取得元と なる URLの 安全性を 確保する ための ホワイトリストと ブラックリストを 取得・設定できます。
Angularアプリケーションの コードで SCE委譲プロバイダーを 使う 場合は、 リソースの ホワイトリスト設定を 適切に 検討してください。
リモートテンプレートの 取得には 安全な 通信手段と して HTTPSを 使い、 リモートエンドポイントの TLS設定が 最新である ことを 確認する。
ドメインや プロトコルに 二重アスタリスクの ワイルドカード ** を 使わない。
必要に 応じて、 多層防御の ために ブラックリストを 作成する。
4. AngularJSのオープンリダイレクト脆弱性 ブラウザー標準の APIには、 $window.locationなど、 ページ遷移を 行う 機能が あります。 Angularでは $locationサービスプロバイダーを 使って 遷移処理を 抽象化し、 $location.url()、$location.path()、$location.hash()など の メソッドを 提供します。 これらを 使って 現在の 遷移先U RLに アクセスし、 必要に 応じて 同期できます。
URLの クエリパラメーターや その 他の URL関連 データに 基づいて 遷移する Angularコードを 使っているかもしれません。
次の 例を 見てみましょう。
この Angularコードは、 たとえば https://www.example.com/path/to/this#referer のような URLを 解析し、 別の ページへ 遷移する 際の ベースと して 使う ことを 意図しています。
しかし、 Webアプリケーションを 閲覧する ユーザーが URLアドレスを 制御できる ため、 ハッシュに 有効な JavaScriptコードを 設定できます。 たとえば https://www.example.com/path/to/this#javascript:alert(1 ) — と すれば、 その URLを 実行できます。
同様に、 window.location.hrefに ユーザー入力を 設定すると、 たとえば ハッシュを 使った JavaScriptインジェクションの 例と 同じ 結果に なります。
AngularJSセキュリティの基礎 オープンリダイレクトと JavaScriptコードインジェクションを 防ぐ ための ベストプラクティス:
ユーザー入力を そのまま 使った ページ遷移は 避ける。
ユーザー入力に 基づいて ページ遷移する 必要が ある 場合は、 辞書マップを 使って 入力値と ページまたは URLを 対応付ける。
ページ遷移用URLに ユーザー入力を 連結しない。
要点: ユーザー入力を そのまま ページ遷移に 使う ことで 発生する、 オープンリダイレクトの 問題を 避けましょう。
5. サーバーサイドAngularコードインジェクション サーバーサイドの コードは スクリプトなどの 悪意ある HTMLエンティティを サニタイズまたは エンコードしますが、 クライアント側の AngularJSコンテキストは 認識しません。 その ため、 攻撃者が 中括弧と 追加の JavaScriptペイロードを 含む Angularテンプレート式を 提供すると、 クライアント側の 実行時に 評価され、 インジェクション攻撃に つながる 可能性が あります。
サーバーサイドAngularコードインジェクションを 軽減する ための ベストプラクティス:
サーバーサイドと クライアントサイドの テンプレートを 混在させないでください。 テンプレートは サーバー側または クライアント側の いずれか、 一つの アプリケーションコンテキスト内だけで 扱います。
ng-appディレクティブの 適用範囲を HTMLドキュメントの bodyから、 ページ内の 特定の DOM要素に 限定します。
テンプレートの データを ng-bindまたは ng-bind-htmlに バインドし、 これらの Angularディレクティブが 提供する 出力エンコードと サニタイズ機能に よって、 ユーザー入力が 適切に 処理されるようにします。
ng-non-bindableを 使い、 データが Angularに よって 評価対象の 式と して 扱われないようにして、 Angularコードインジェクションを 軽減します。
要点: サーバーサイドAngularコードインジェクションを 軽減しましょう。
6. DOM操作にAngularの.element jQuery互換APIを使用しない Angularには、 DOMを 直接 検索・ 操作する ための jQueryライクな API互換性 (jqLite)を 提供する angular.element() APIが あります。
DOMへの アクセスや 操作に 便利な 方法に 思えるかもしれませんが、 安全でない DOMインジェクションに よって、 インジェクション脆弱性が 生じる 可能性が あります。
次のような シンプルな Angularテンプレートを 考えてみましょう。
次は、 angular.element()を 使って ページを 操作する、 対応する Angularコントローラーです。
問題は element.after()に あります。 これは、 jQuery独自の after APIとの 互換性を 保つため、 エンコードや サニタイズを 行わずに $scope.contentの 内容を DOMに 追加します。 この 変数に 悪意の ある 内容が 含まれていると、 Angularの 保護機能が 適用されず、 XSS の 被害を 受ける 可能性が あります。
Angular公式ドキュメントの https://docs.angularjs.org/api/ng/function/angular.element で、 angular.elementの 詳細を ご覧ください。
重要な ポイント: Angularの angular.element() jQuery互換APIを 使った DOM 操作は 避けましょう。 DOMに HTML要素を 直接 作成する ことで、 クロスサイトスクリプティング脆弱性に つながる 可能性が あります。
7. Angularのセキュリティリンターを使う JavaScript開発では リンターが 広く 使われており、 開発者は ESLintのような 人気プロジェクトを、 機能を 拡張する プラグインと 組み合わせて 利用する ことが よく あります。 eslint-plugin-angular は、 Angularの 一般的な コーディング規約や ガイドラインに 役立ちます。 セキュリティ関連の ルールも 含まれており、 その 1つである no-jquery-angularelementは、 angular.elementオブジェクトを jQueryまたは $ . で ラップする ことを 禁止します。
公式ドキュメントに よると、 ESLint プラグインが 問題を 検出する 例は 次の とおりです。
angular.element ()の 使用が セキュリティ上の 問題と なる 理由が わからない 場合は、 前の セクション 「 DOM 操作に Angularの .element jQuery互換APIを 使用しない 」を お読みください。
重要な ポイント: 静的コード解析ツールを 使って、 安全でない コードの 検出を 自動化し、 開発の 早い 段階で 問題が 見つかった ときに 開発者へ 通知しましょう。 AngularJSの セキュリティの 基本と なる セキュリティリンター:
8. Angularのサードパーティコンポーネントの脆弱性を検出して修正する Webアプリケーションの 構築に あたり、 Angularの コアや 拡張コンポーネントに 加えて、 オープンソースパッケージを 利用している 可能性は 高いでしょう。 実際、 AngularJSプロジェクト自体にも 脆弱性が あります。 Snykに よる JavaScriptフレームワークの セキュリティ に 関する 調査では、 AngularJSの 1.x系全体で 20件を 超える セキュリティ脆弱性が 見つかっています。
さらに、 Angularベースの Webアプリケーションの 構築に 使う 依存関係にも、 セキュリティ脆弱性が 含まれている 可能性が あります。 次の 表に 示すように、 脆弱性に よっては、 現時点で 修正方法が 提供されていない ものも あります。
脆弱性をスキャンする AngularJSの セキュリティスキャナーを お探しですか? Snykを 使い、 GitHubまたは Bitbucketの プロジェクトを 接続 すれば、 AngularJSの セキュリティテストを 実施し、 フロントエンドプロジェクトの 脆弱性を 常に 把握できます。 Snykが 自動的に 脆弱性を 検出し、 修正用の プルリクエストを 作成します。
AngularJSの セキュリティ 問題を 手早く 特定するには、 Snyk CLIを 使う 方法も あります。
Snyk testを 実行すると、 検出された 脆弱性と 脆弱な 依存関係の パスが 表示されます。 これに より 依存関係 ツリーを たどり、 どの モジュールが 脆弱性を 持ち込んだのかを 把握できます。
npm auditを 使っている 場合、 Snykが 報告する AngularJSの セキュリティ脆弱性を 見逃している 可能性が あります。 npm auditは Reactの 3つの 脆弱性も すべて 見逃す ため、 開発者に 誤った 安心感を 与えてしまいます。
出典: https://snyk.io/blog/angular-vs-react-security-bakeoff-2019/
Snykは、 修正版への アップグレードに 向けた 具体的な 修正アドバイスを 提供し、 リポジトリに 自動で プルリクエストを 作成します。 修正が 提供されていない 場合は、 Snykが 提供する パッチを 適用して 脆弱性を 緩和する こともできます。
AngularJSの セキュリティスキャナーに 近い ものを お探しなら、 オープンソースの 依存関係を 追跡し、 脆弱性の 通知を 受け取り、 脆弱性が 見つかったら 修正できる Snykから 始めましょう。
重要な ポイント: AngularJSには これまでに 20件を 超える 脆弱性が あり、 ダウンロード数が 数百万件に 達する Angularコンポーネントにも、 依然と して 脆弱性が 残っています。
9. Angularアプリケーションに組み込まれたCSRF対策 クロスサイトリクエストフォージェリ (CSRF、 XSRF) は、 フォームを 送信する APIリクエストなど、 ユーザーの 意図しない 操作を 実行するように 仕向ける Webセキュリティ攻撃です。
CSRF脆弱性を 緩和する 方法の 1つは、 ランダムに 生成した トークンを 使う ことです。 さらに 望ましいのは、 リクエストが 信頼できる ことを 認証する 手段と して、 暗号学的な ノンスを 使用する ことです。
Angularには CSRFトークンの 組み込みサポートが あり、 サーバーから 送信される XSRF-TOKENなど、 特定の 命名規則に 従った Cookieを 読み取り、 その 値を Angularアプリケーションから 送信する 後続の HTTPリクエストに 追加します。
AngularJSでは、 CSRFトークンの 処理は すべて $http サービス内で 行われます。 新しい Angularバージョンでは、 公式サポート対象の @angular/common/httpモジュールに 含まれる HttpClient から も 利用できます。 また、 $http.xsrfCookieName APIなどを 使って、 CSRFトークンの Cookie名や 全般的な 動作を 設定できます。
重要な ポイント: Angularには、 クライアント側で $httpサービスを 介して CSRFトークンを 処理する 組み込みサポートが あります。 独自に 実装せず、 この サービスを 使いましょう。
10. Angularに組み込まれたCSP対応 インラインJavaScriptコードの 評価を 禁止するなど、 一般的な CSP制限と 競合する Angularの 機能も あります。 しかし、 推奨されない CSPの 全面的な 無効化ではなく、 Angularの ngCspディレクティブを 使えば、 CSP設定との 互換性を 確保できます。
コンテンツセキュリティポリシー (CSP)は、 信頼ポリシーを 設定できる Web標準です。 主に セキュリティを 強化する 多層防御と して 利用され、 XSSインジェクションなどの 問題の 緩和に 役立ちます。
AngularJSには CSP関連の 組み込み制御が ありますが、 有効に すると 一部の 機能が 制限されます。 たとえば、 eval()が 許可されないため、 インラインスクリプトや式は 使えません。 一方で、 AngularJSの 一部機能では 内部的に これらが 必要です。
CSPに ついては、 Mozillaの Webサイトに ある おすすめの 解説 と、 Angular APIドキュメントの ngCspディレクティブ を ご覧ください。
重要な ポイント: コンテンツセキュリティポリシー (CSP)の 導入は、 セキュリティを さらに 強化する 重要な ステップです。 特に、 クロスサイトスクリプティング攻撃の 緩和に 役立ちます。
AngularJSセキュリティの 基本と なる 10の ベストプラクティス:
「Angular流」の 実装で XSSから 保護する
Angularの DOM関連の 入力インジェクションを 避ける
信頼できない ソースから Angularテンプレートを 動的に 読み込まない
AngularJSの オープンリダイレクト脆弱性
サーバーサイドの Angularコードインジェクション
DOM 操作に Angularの .element jQuery互換APIを 使用しない
Angularの セキュリティリンターを 使う
Angularの サードパーティコンポーネントの 脆弱性を 検出して 修正する
Angularアプリケーションに 組み込まれた CSRF対策
Angularに 組み込まれた CSP対応
AngularJSセキュリティの ベストプラクティス・チートシートを ダウンロード !