Angular Material(v15)でのCSP対応方法
普段フロントエンドの開発では、Angularを使用しています。
UIデザインもAngular Materialを使用しています。サイトを公開するにあたり、Security対策としてContent Security Policy(以下CSP)の設定を設定します。
この記事では、Angular Materialを使用時の設定について共有します。
CSPとは
最初に、簡単ですがContent Security Policy(以下CSP)をおさらいです。
コンテンツセキュリティポリシー (CSP) | MDN Web Docs
ンテンツセキュリティポリシー (CSP) は、クロスサイトスクリプティング (Cross-site_scripting) やデータインジェクション攻撃などのような、特定の種類の攻撃を検知し、影響を軽減するために追加できるセキュリティレイヤーです。 これらの攻撃はデータの窃取からサイトの改ざん、マルウェアの拡散に至るまで、様々な目的に用いられます。
MDN Web Docs
設定は、HTTPヘッダーまたはHTMLもMetaタグで設定します。
サイト内のJavaScript、CSS、画像などのメディアの取得元を定義しておくことで、ブラウザが定義外の取得元の参照があると制限してくれます。そのため、アプリケーションにクロスサイトスクリプティングの脆弱性があった際に不正に外部のデータを読み込むようなことを防ぐことができます。
Angularでの推奨設定
Angular公式ドキュメントのセキュリティのページに設定が記載されています。
Angular 16からnonceというのに対応していますが、この記事では、15までの対応方法について記載します。
https://v15.angular.io/guide/security#content-security-policy
Content Security Policy (CSP) is a defense-in-depth technique to prevent XSS. To enable CSP, configure your web server to return an appropriate
Content-Security-Policy
HTTP header. Read more about content security policy at the Web Fundamentals guide on the Google Developers website.The minimal policy required for brand-new Angular is:
default-src ‘self’; style-src ‘self’ ‘unsafe-inline’;
Angular – Security
Angularで最小限必要なポリシーが記載されています。
ここで注目のポイントは、style-srcに‘unsafe-inline’が含まれていることです。
unsafe-inlineは、inline (Styleではstyleタグでの記述)を許可するというものですが、キーワードにunsafeがついてる通り、CSPではunsafe(安全ではない)とされています。
W3CのCSPでも以下のように、unsafe-inlineとdataは使用すべきではないと記載されています。
In either case, developers SHOULD NOT include either
https://www.w3.org/TR/CSP3/'unsafe-inline'
, ordata:
as valid sources in their policies. Both enable XSS attacks by allowing code to be included directly in the document itself; they are best avoided completely.
ですので、Angular 15までは、styleについては、unsafe-inlineを含めないといけないという制約があります。
個人的には、styleに関してなので、そこまで重大な課題ではないと考えています。
Angular Material使用時の注意点
課題
Angular Materialを使用している場合、ng buildで生成したアプリケーションで、上記のCSPの設定を行うと、consoleにエラーが表示されます。
原因は、2つあります。
1つ目は、フォントを使用しているため、fonts.gstatic.comへの読み込みが制限されてしまったためです。
2つ目は、出力されたindex.htmlのcssのタグが、ファーストビューを早くするために、media=”print”にし、onloadでmediaを変更するというJavaScriptが含まれており、CSPによりonloadイベントのJavaScriptが実行されないためです。
1<link rel="stylesheet" href="styles.6507e0fc35322572.css"
2 media="print" onload="this.media='all'">
回避策
1つ目の回避策は、CSPの設定にフォントの取得先を追加します。
font-src ‘self’ fonts.gstatic.com;
2つ目の回避策は、angular.jsonで、build時のoptimizationの設定で、styleのinlineCriticalをfalseにすることで回避できます。
1 "configurations": {
2 "production": {
3 "optimization": {
4 "scripts": true,
5 "styles": {
6 "minify": true,
7 "inlineCritical": false
8 },
9 "fonts": true
10 }
11 },
12
この設定にして、buildすると、以下のようにonloadがなくなります。
1<link rel="stylesheet" href="styles.6507e0fc35322572.css" />
最終的なCSPの設定
Angular公式の最初の設定では、default-srcとstyle-srcしか設定されていません。
指定していない項目は、default-srcが使われるのですが、一部の項目では使用されないため、個別で指定する必要があります。
default-src ‘self’; style-src ‘self’ ‘unsafe-inline’; font-src ‘self’ fonts.gstatic.com; form-action ‘self’; base-uri: ‘self’; frame-ancestors: ‘self’; navigate-to: ‘self’;
form-action, base-uri, frame-ancestors, navigate-toが、default-srcをfallbackしないので個別で設定します。
当然ですが、font-srcのように、アプリとして必要なものは追加する必要があります。