Angular(>=2.x)はセキュリティに対してどのような提案をしているか


このページを読んで、肝の部分をまとめています。
基本的には翻訳をやわらかくしたものです。

(補足・見解は、こんなかんじで括弧書きしてます)

執筆時バージョン:v4.3.6

Webの脆弱性全般の説明

具体的には OWASP Guide Project 参照とのこと。

ベストプラクティス(実質推奨事項)

  • Angularのバージョンは最新に保つようにしましょう。
  • ローカルにコピーされた(node_moduleとか)Angularを触らないようにしましょう。もし改善が必要な場合はコミュニティにその情報を展開し、プルリクエストで本体を改善しましょう。
  • Angular APIのドキュメントで"Security Risk"とマークされた機能を使用するのを避けましょう。

クロスサイトスクリプティング(XSS)に対して

Angularとしては・・・

”Angularのテンプレートは実行可能なコードである”ことが前提となります。つまり、入力した内容はちゃんとサニタイズ(ゴミを取り除いてきれいにすること)、エスケープを、アプリケーションで実装しなければなりません。

オフラインテンプレートコンパイラ を活用したりして、ユーザ入力がテンプレートとして処理されないようにしましょう。

Angularは何かエスケープ処理してる?

モデルを画面に埋め込むやり方は2つあります。
1つ(前者、p.e2e-inner-html-interpolated)は、エレメントの間に直接htmlSnippetを埋めこんでいます。
もう1つ(後者、p.e2e-inner-html-bound)は、innerHtmlプロパティを介してhtmlSnippetを埋め込んでいます。

<h3>Binding innerHTML</h3>
<p>Bound value:</p>
<p class="e2e-inner-html-interpolated">{{htmlSnippet}}</p>
<p>Result of binding to innerHTML:</p>
<p class="e2e-inner-html-bound" [innerHTML]="htmlSnippet"></p>

このとき、前者は常にHTMLエスケープが行われます。<>のような記号は平文として画面に文字表示されます。

HTMLを解釈・処理して画面に表示するには、後者のように、innerHTMLなどのHTMLプロパティにバインドします。
しかし解釈・処理されるため、XSS脆弱性が発生します。

これに対応するため、AngularではHTMLプロパティにバインドしたとしても、<script>タグは自動的に削除されます。

  htmlSnippet = 'Template <script>alert("0wned")</script> <b>Syntax</b>';

htmlSnippetの値が上のようになっているとき、画面上に表示されるテキストは次のようになります。

Template alert("Owned") ** Syntax **

alert("Owned")は平文表示され、Syntaxは太字になる )

直接DOM APIを使用することは避けましょう

ElementRef等を使用すると、上述のようなAngularの処理の恩恵が受けられなくなります。

Content Security Policy(CSP)を有効にしましょう

HTTPヘッダーにContent-Security-Policyを設定し、CSP を有効にしましょう。

サーバ側でのXSS防止

サーバからAngularのテンプレートを送信しないでください。
サーバからAngularのテンプレートを送信してアプリケーションで解釈させる、ということは、ユーザ入力をテンプレートとして解釈できることと同義です。

(テンプレートHTMLをサーバから送信してブラウザ側でAngular Compilerで処理することは、ng serveのホットリロードでは有効だけど、本番では使っちゃダメ!)

信頼済みのスクリプトを実行させる方法

信頼済みのスクリプトや<iframe>を実行させるために、DomSanitizer をインジェクトしてbypassSecurityTrust...とつくメソッドを使用して、Angularに信頼済みであることを指示できます。
ですが、これは悪意のあるコードが組み込まれる可能性を高めることになるので、注意して使用して下さい。

HTTPレベルの脆弱性に対して

Angularは次の2つの脆弱性防止のサポートを組み込んでいます。根本的にはサーバで対応する脆弱性ですが、その仕組みをフロント側でも組み込みやすいような機能をもっています。

  • cross-site request forgery (CSRF or XSRF)
  • cross-site script inclusion (XSSI)

XSRF

XSRFは、悪意のあるリクエストを目的のサーバ(example-bank.com)に送信する、悪質なコードを持つ偽りのサイト(evil.com)に、ユーザを欺いて誘い込むものです。

XSRFを防ぐ一般的な方法として、サーバでランダムな認証コードを生成し、Cookieでクライアントに送る方法があります。
クライアントは後続のリクエストではその認証コードをHTTPヘッダーに設定することで、サーバ側でヘッダーとCookieの一致によってクライアントを判断できます。
Cookieは同一オリジンの場合のみ読み取り可能であるため、evil.comでは本来のサーバのCookieを読み取ることはできないため、この方法は効果的です。

Angularの HttpClient では、この手法の半分(クライアント側)のサポートが組み込まれています。

XSSI

この攻撃は、返されたJSONがJavaScriptとして実行可能な場合にのみ成功します。 サーバーは、すべてのJSONレスポンスのプレフィックスを使用して攻撃を防ぎ、慣習的に、よく知られている文字列 ")]} '、\ n"を使用して実行不可能にすることができます。

HttpClient では、JSONパースを行う前に、これらの文字列を取り除きます。

おまけ

CSPとは

サーバから送信するHTTPヘッダに次のようなものを加えることで、意図しないスクリプトを実行できないようにします。

Content-Security-Policy: script-src 'self' https://apis.google.com

XSSIとは

XSSIはXSSの一種で、ブラウザが他のドメインやサーバーでホストされている画像やスクリプトなどのリソースをウェブページに含めることを妨げないという利点を利用しています。

たとえば、スクリプトは、開発者が特定のページを作成するために必要な機能を提供することがあります。これを含む多くのサイトには、https://developers.google.com/speed/libraries/#jquery でホストされているJavaScriptライブラリjQueryが含まれています。 ただし、この条件は、あるユーザーが別のユーザーのドメインにアクセスしているときにそのユーザーのデータを読み取るために悪用される可能性があります。

たとえば、Bank ABCのサイトにユーザーの個人アカウント情報を読み取るスクリプトがある場合、
ハッカーは、Bank ABCのクライアントがハッカーのサイトにアクセスするたびに、そのスクリプトを自分の悪意のあるサイト(www.fraudulentbank.com)に含めて、Bank ABCのサーバーから情報を引き出すことができます。

XSSはユーザ入力部分にスクリプトを入力するが、XSSIは自分のサイトにホストしている悪意のあるスクリプトをターゲットのBank ABCのWebサイトにロードさせる、ということでしょうか?

なるほどわからん。