AngularJS TIPS
コンテンツ・セキュリティ・ポリシーを利用する(ng-csp)
セキュリティフレームワーク「CSP」による制限ポリシーを有効にした場合に、AngularJSでは特定のケースでエラーとなる。そのケースの内容と回避方法を解説する。
コンテンツ・セキュリティ・ポシリー(Content Security Policy:CSP)とは、クロスサイト・スクリプティング(XSS)に代表される、よくあるアプリへの攻撃を軽減するためのセキュリティフレームワークです。あらかじめ設定したポリシーによって、ブラウザー(アプリ)に制限を加えることで、アプリの安全性を高めます。制限できる主な事項には、以下のようなものがあります。
- JavaScript疑似プロトコル(
href="javascript:~"
)の禁止 - インラインのスクリプト/スタイルシートの禁止
- インライン・イベントハンドラー(
onclick
など)の禁止 eval
関数をはじめ、Function
コンストラクター、setTimeout
/setInterval
関数などへの文字列コードの禁止- 異なるドメインからのスクリプト/スタイルシートのインポートを禁止
- ブラウザープラグイン(Flash、Javaなど)の利用を禁止
これらの制限ポリシーは、レスポンスヘッダーによってブラウザーに通知され、ブラウザーの挙動を制限することになります。例えばPHPで、ポリシー設定のためのヘッダーを出力するには、以下のようにします。もちろん、理屈が分かっていれば、他の言語でも同じように記述できます。
<?php
header("Content-Security-Policy: default-src 'self' ajax.googleapis.com");
?>
|
CSPを有効化するのは、Content-Security-Policy
ヘッダーの役割です。ヘッダー値にはさまざまなポリシー情報を指定できますが、まずここでは、現在のホスト(self
)とajax.googleapis.com
への参照だけを許可していると理解しておいてください。Content-Security-Policy
ヘッダーの詳細については、「CSP (Content Security Policy) - MDN」などの資料を参照することをお勧めします。
AngularJSとCSP
さて、まずはCSPを有効にした状態で、AngularJSアプリを動作してみましょう。
<?php
header("Content-Security-Policy: default-src 'self' ajax.googleapis.com");
?>
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8" />
<title>AngularTips</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<script src="scripts/csp.js"></script>
</head>
<body ng-controller="MyController">
<div ng-cloak>{{1 + 3}}</div>
</body>
</html>
|
angular.module('myApp', [])
.controller('MyController', ['$scope', function($scope) {
}]);
|
angular.js:3543 Refused to apply inline style because it violates the following Content Security Policy directive: "default-src 'self' ajax.googleapis.com". Either the 'unsafe-inline' keyword, a hash ('sha256-1PxuDsPyGK6n+LZsMv0gG4lMX3i3XigG6h0CzPIjwrE='), or a nonce ('nonce-...') is required to enable inline execution. Note also that 'style-src' was not explicitly set, so 'default-src' is used as a fallback.
|
AngularJSでは、もともとがCSPを意識した行儀のよいコードを提供していますが、以下のケースで例外的にCSPの制約に抵触します。
- パフォーマンス最適化のために
Function
コンストラクターを使用 - インラインのスタイルシートを出力(
ng-cloak
ディレクティブ)
結果、上のようなエラーが発生しているわけです。これを解消するのがng-csp
ディレクティブの役割です。
ng-cspディレクティブの基本と注意点
ng-csp
デイレクティブ(属性)は、ルート要素に付与するだけです。
<?php
header("Content-Security-Policy: default-src 'self' ajax.googleapis.com");
?>
<!DOCTYPE html>
<html ng-app="myApp" ng-csp>
|
果たして、先ほどのエラーが出力されなくなったことが確認できます。
このように、ng-csp
ディレクティブの使い方は誤解のしようもないものですが、注意すべき点もあります。
1パフォーマンスはやや低下する
最適化のために使われていたFunction
コンストラクターなどが無効化されますので、いくらかパフォーマンスが低下する可能性があります。ただし、パフォーマンスに影響するコード(Angular式)は限定されていますので、さほど気にする必要はないでしょう。
2アプリではCSPの制約を守る必要がある
ng-csp
ディレクティブは、あくまでAngularJS本体をCSPに即したコードで動作するための仕組みです(=CSPの制約を取り払っているわけではありません)。よって、アプリを実装する際には、本稿冒頭で触れたような制約を意識しなければなりません。
3インライン・スタイルシートは明示的にインポートする
ng-csp
ディレクティブによって、それまで生成されていたインライン・スタイルシートはインポートされなくなります。よって、ng-cloak
ディレクティブを利用するに際しては、以下のように明示的にスタイルシートをインポートしてください。
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-csp.css" />
|
API:ngCsp(ng-csp)|ngCloak(ng-cloak) カテゴリ:ng(コアモジュール) > directive(ディレクティブ)
※以下では、本稿の前後を合わせて5回分(第52回~第56回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
52. ルーティングの挙動/設定をカスタマイズするには?($routeProviderプロバイダー)
「テンプレートを文字列で指定(templateパラメーター)」「リダイレクト時の規則をカスタマイズ(redirectToパラメーター)」「html5モードに切り替える」という、特によく使われる3つのカスタマイズ方法を取り上げる。
53. 配列/オブジェクトをコピーするには?(copy)
配列のコピーで、JavaScript標準のconcatメソッドを使う場合とAngularJSのcopyメソッドを使う場合の違いを説明。シャローコピーとディープコピーとは?
54. 【現在、表示中】≫ コンテンツ・セキュリティ・ポリシーを利用する(ng-csp)
セキュリティフレームワーク「CSP」による制限ポリシーを有効にした場合に、AngularJSでは特定のケースでエラーとなる。そのケースの内容と回避方法を解説する。
55. 複数のオブジェクトを結合するには?(extend/merge)
angular.extendメソッドを利用して、既存の複数のオブジェクトを結合する方法と注意事項を解説。また、入れ子になったオブジェクトを再帰的にマージする方法も説明する。
56. AngularJSの管理外でサービスを注入するには?($injector)
AngularJSの管理外でも、$injectorサービスを使ってサービスを手動でインスタンス化することで、AngularJSが提供するサービスを利用できる。その基本的な利用方法を説明する。