XSS対策としてCSPを設定する方法
あなたのサイトはXSS対策できていますか?
今回はセキュリティ対策のひとつであるCSP(Content Security Policy)について、解説していこうと思います。
そもそもXSS(クロスサイトスクリプティング)をご存知でしょうか?
実はXSSにも種類がありこれを理解するところから始まります。
※XSSの種類についての解説は割愛させていただきます
- 反射型XSS
- 格納型XSS
- DOM Based XSS
CSPによって信頼したコンテンツのみに絞ることでXSS攻撃を大きく軽減できます。
ここから実際にCSPの基礎概念や設定方法を紹介します。
※CSPはXSS専用対策ということではありません
CSP基礎概念
主なCSPの役割は以下の通りです。
- データの窃取
- サイトの改ざん
- マルウェアの拡散
どのセキュリティ対策にも言えることであるためCSPの設定を追加するだけで、より堅牢なサイトに成長させることができます。
CSPでは信頼したドメインやコンテンツを指定できるため、サイト運用者が把握していないスクリプトの追加、つまりXSS攻撃を回避することにつながります。
設定方法は2つあります。
- HTTP ヘッダー
- metaタグ
推奨されるのはHTTPヘッダーになりますがサードパーティを使用している場合や、レンタルサーバーなどでヘッダーに設定できない場合はmetaタグで設定を行えます。
また、ブラウザによってはCSPの設定が効かないことがあるため、設定後は検証することを強くおすすめします。
CSP設定
今回は利用者が多そうなのでmetaタグで設定する想定で以下記載していきます。
CSP用のmetaタグをheaderタグ内に記述します。
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'self';">
</head>
content属性に信頼しているドメインやコンテンツを設定していきます。
弊社でおすすめしたいディレクティブは以下の9種類になります。
CSPおすすめ設定
- upgrade-insecure-requests
- HTTPのリクエストをHTTPSに置き換え
- default-src
- 他オプション設定をdefaultで設定
- 他ディレクティブで明示されていればdefault-srcの設定は上書かれる
- connect-src
- aタグやXMLHttpRequestなどのAPIタグ用
- object-src
- embed、object、appletタグ用
- base-uri
- baseタグ用
- script-src
- scriptタグ用
- child-src
- iframeタグ用
- img-src
- imgタグ用
- font-src
- フォントリソース用
弊社では信頼できるドメインを各ディレクティブで設定しています。
せっかくなのでその一例を記載しておきます。
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests; default-src 'self'; script-src 'self' *.googletagmanager.com *.google-analytics.com;">
インラインのスクリプトやスタイルは上記設定だけだと排除されてしまうので注意してください。
もし、インラインを設定に含めたい場合は2つ方法があります。
- nonce
- ハッシュ
どちらもランダムな文字列での設定になります。
要するにmetaタグとインラインコードで同じ文字列を持つことで、信頼されるインラインコードであることを証明します。
nonceの設定の方が簡単なので以下設定方法を記載します。
metaタグ側の設定
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'nonce-2726c7f26c';">
インラインコード側の設定
<style nonce="2726c7f26c">
#inline-style {
background: red;
}
</style>
設定は以上になります。
おまけ
CSP独自設定ディレクティブ
DOM Based XSS対策により有効な独自設定ができるディレクティブがあります。
これらを使用してサイト独自のセキュリティ対策ができるのでぜひお試しください。
- require-trusted-types-for
- trusted-types
全拒否ディレクティブ
あまり活用する機会はなさそうですがjs全拒否設定も記載しておきます。
以下のように他ディレクティブでもnoneは使用できます。
<meta http-equiv="Content-Security-Policy" content="script-src 'none'">
nonce用ランダム文字列作成
Pythonでランダム文字列を10文字で作成しています。
import base64
import random
import string
result = ''.join(random.choice(string.ascii_uppercase) for _ in range(10))
print(result)
print(base64.b64encode(result.encode()))
さいごに
CSP設定は制限をかけるものであるため、設定に漏れがあった際は画面に表示されなくなってしまいます。
設定する前に制御すべき設定内容の洗い出しから始めることを強くおすすめします。