このガイドでは、Discourse におけるクロスサイトスクリプティング(XSS)攻撃を緩和するために、コンテンツセキュリティポリシー(CSP)を使用する方法について説明します。CSP の基礎、設定、およびベストプラクティスをカバーしています。
必要なユーザーレベル:管理者
まとめ
コンテンツセキュリティポリシー(CSP)は、クロスサイトスクリプティング(XSS)やその他のインジェクション攻撃から保護するための、Discourse における重要なセキュリティ機能です。このガイドでは、CSP の基礎、Discourse での実装方法、およびサイトでの設定方法について解説します。
コンテンツセキュリティポリシーとは?
コンテンツセキュリティポリシーは、クロスサイトスクリプティング(XSS)やデータインジェクション攻撃など、特定の種類の攻撃を検出および緩和するための追加のセキュリティ層です。CSP は、信頼できるコンテンツソースを指定し、ブラウザに対してそれらの信頼できるソースからのリソースのみを実行またはレンダリングするように指示することで機能します。
XSS は依然として最も一般的な Web の脆弱性の一つです。CSP を実装することで、Discourse は信頼できるソースからのスクリプトのみをロードおよび実行することを許可し、XSS 攻撃のリスクを大幅に低減します。
Discourse の CSP 実装
Discourse バージョン 3.3.0.beta1 以降、Discourse は「strict-dynamic」CSP を実装しています。このアプローチでは、script-src ディレクティブに単一の nonce- 値と strict-dynamic キーワードを使用します。コアおよびテーマ内のすべての初期の <script> タグには、自動的に適切な nonce= 属性が割り当てられます。
デフォルトのポリシーには、以下のディレクティブが含まれています。
script-src:JavaScript の有効なソースを指定
worker-src:ServiceWorker スクリプトの有効なソースを指定
object-src:プラグイン(Flash、Java など)の実行をブロック
base-uri:<base> 要素の URL を制限
manifest-src:Web アプリマニフェストの URL を制限
frame-ancestors:どのサイトが iframe 内に Discourse インスタンスを埋め込むことができるかを制御
upgrade-insecure-requests:HTTP リクエストを自動的に HTTPS にアップグレード(force_https が有効な場合に含まれる)
Discourse での CSP の設定
利用可能な設定
content_security_policy:CSP の有効化または無効化(デフォルト:オン)
content_security_policy_report_only:CSP レポートオンリーモードの有効化(デフォルト:オフ)
content_security_policy_script_src:デフォルトの script-src ディレクティブ を拡張可能
content_security_policy_frame_ancestors:frame_ancestors ディレクティブ を有効化(デフォルト:オン)
CSP の有効化方法
管理パネルに移動
セキュリティ設定へ移動
content_security_policy 設定を見つけ、有効になっていることを確認
CSP を完全に有効にする前に、潜在的な問題を確認するために、CSP レポートオンリーモードから開始することをお勧めします。
content_security_policy_report_only 設定を有効化
ブラウザのコンソールで CSP 違反を監視
必要に応じて CSP を拡張し、正当な違反に対処
誤検知がないことを確信したら、レポートオンリーモードを無効化し、CSP を完全に有効化
デフォルトの CSP の拡張
追加のスクリプトソースを許可する必要がある場合は、content_security_policy_script_src 設定を使用して script-src ディレクティブを拡張できます。以下を追加できます。
ハッシュソース
'wasm-unsafe-eval'
'unsafe-eval'(注意して使用してください)
例:
'sha256-QFlnYO2Ll+rgFRKkUmtyRublBc7KFNsbzF7BzoCqjgA=' 'unsafe-eval'
'unsafe-eval' や他の寛容なディレクティブを追加する際は注意してください。これらは CSP の効果を低下させる可能性があります。
CSP とサードパーティとの統合
Google タグマネージャー、Google アナリティクス、広告サービスなどのサードパーティサービスを使用する場合は、CSP 設定を調整する必要がある場合があります。Discourse バージョン 3.3.0.beta1 以降のほとんどの場合、‘strict-dynamic’ CSP の実装により、追加の設定なしで外部スクリプトが動作します。
問題が発生した場合は、以下を行う必要がある場合があります。
ブラウザのコンソールを監視して、必要なスクリプトソースを特定
必要なソースを content_security_policy_script_src 設定に追加
外部リソースをロードする広告サービスなどの複雑な統合の場合、ドメイン間レンダリングを有効にする必要があるかもしれません(これを行う discourse-adplugin の例 PR を参照)。
ベストプラクティス
潜在的な問題を確認するために、CSP レポートオンリーモードから開始
正当な違反を解決するにつれて、CSP を徐々に強化
CSP 設定を定期的にレビューし、必要に応じて調整
'unsafe-eval' や 'wasm-unsafe-eval' のような寛容なディレクティブを追加する際は注意
最新の CSP の改善を活用するために、Discourse インスタンスを最新の状態に保つ
よくある質問
Q: CSP 違反レポートが多数表示されています。心配すべきですか?
A: 多くの CSP 違反は誤検知であり、ブラウザ拡張機能や他の無関係なスクリプトが原因であることが多いです。サイトの機能に関連する違反に対処することに集中してください。
Q: Google AdSense や他の広告ネットワークと CSP を併用できますか?
A: はい、ただしより寛容な CSP 設定を使用する必要がある場合があります。レポートオンリーモードから開始し、報告された違反に基づいて設定を調整してください。
Q: CSP の問題をトラブルシューティングするにはどうすればよいですか?
A: ブラウザの開発者ツールを使用して、CSP 違反メッセージをコンソールで監視してください。これにより、どのリソースがブロックされているか、その理由を特定できます。
追加リソース
「いいね!」 56
I added a note about this to our public security.md file
「いいね!」 13
pmusaraj
(Penar Musaraj)
2019 年 1 月 15 日午後 4:36
3
As of this commit , we’ve turned off CSP violations reports by default because the vast majority of the reported violations are false positives.
To illustrate this, here is a screenshot of logs from a site running Discourse with CSP enabled and reporting enabled (filtered using “CSP Violation”):
All of the reported violations are not related to the site’s code:
violations with ‘minisrclink.cool’ or ‘proxdev.cool’ in the URL have nothing to do with Discourse, they’re likely coming from a browser extension
the Google Analytics violation reports are also not legitimate. They are triggered by Firefox in privacy mode, or Firefox with a privacy extension enabled (like DuckDuckGo Privacy Essentials).
Violations with ‘inline’, ‘data’ or ‘about’ are triggered by extensions as well. It’s not shown in the screenshot above, but these violations have some more details in the env tab of the log. In there, under script-sample, some of these violations had code like BlockAdBlock or window.klTabId_kis or AG_onLoad, which come from the AdBlock, Kaspersky, and AdGuard extensions, respectively. (I found this repo: CSP-useful/csp-wtf/README.md at master · nico3333fr/CSP-useful · GitHub very useful in helping explain some of these reports.) Some of these violations will have safari-extension or user-script in the source-file variable (again, in env), so that points to Safari extensions as the culprit for the violation.
In other words, there’s a lot of noise in CSP violation reports, so it’s not useful to log them at all times. They might be helpful while you are configuring CSP, but the reporting should be off during the normal operation of a site.
A few final notes: if you site is using a tag manager (like Google Tag Manager or Segment) you need to load the site in your browser, and carefully examine the violations in the console. These tools load third-party scripts from third-party domains and/or inline scripts so you need to carefully whitelist each of them using the source URL or the hash of the inline script (Chrome usefully includes the hash of inline scripts in the console error statement).
If your site uses an advertising service (like Google Ad Manager, Adsense, etc.) you probably will have to use a very permissive policy:
In the screenshot above, the policy allows any script from a https: source and any inline script. (In the future, this might be replaced by the strict-dynamic keyword, but as of this writing, strict-dynamic isn’t supported by Safari or Edge.)
「いいね!」 24
codinghorror
(Jeff Atwood)
このトピックを分割しました:
2019 年 4 月 3 日午前 6:03
12
Please note that Safari doesn’t understand some parts of CSP, and this is normal:
You can safely ignore the CSP errors in Safari, you’ll see those on all sites, it just means Safari doesn’t understand worker-src and report-sample .
I guess we need to wait for Safari to be updated?
「いいね!」 12
I’m having trouble configuring, which recommendation?
my forum: forum.meuxbox.com.br
link: White blank advertisement
「いいね!」 2
pmusaraj
(Penar Musaraj)
2020 年 1 月 29 日午後 8:54
22
It depends on what URLs your ads are requesting. You can look at your browser’s console to see them.
See also the relevant section from the OP:
xrav3nz:
4. Third-Party Script / Service Integration
Different integrations will have different requirements, but can be addressed similarly.
You could look up the integration’s recommended CSP whitelist, and extend the default CSP accordingly. I suggest simply turn on CSP Report Only mode in Discourse , and watch your console to determine which resources you’ll need to whitelist to make your integrations work.
This is especially important when using third-party script bundlers like Google Tag Manager or Segment, because these bundlers might load many third-party or inline scripts. (You might even end up adding 'unsafe-inline' when using Segment or GTM, even though this definition should be avoided as much as possible.)
「いいね!」 4
adrelanos
(Adrelanos)
2020 年 6 月 2 日午後 4:07
24
Feature-Policy](Permissions-Policy - HTTP | MDN ) を追加していただけますか?
私はこれを 1 年以上使用しています(ホストは nginx)。
add_header Feature-Policy “geolocation ‘none’; midi ‘none’; notifications ‘self’; push ‘none’; sync-xhr ‘none’; microphone ‘none’; camera ‘none’; magnetometer ‘none’; gyroscope ‘none’; speaker ‘none’; vibrate ‘none’; fullscreen ‘none’; payment ‘none’;”;
Content-Security-Policy ヘッダーに以下の内容を追加するのは妥当でしょうか?これは私が正常に使用している設定です(ホストの nginx によって追加され、Discourse 組み込みの CSP の上に設定されています):
default-src 'none'
style-src 'self' domain 'unsafe-inline'
img-src https://*.domain.org data: blob: 'unsafe-inline'
font-src 'self' domain
connect-src 'self' domain
manifest-src 'self' domain
「いいね!」 3
jomaxro
(Joshua Rosenfeld)
2020 年 6 月 2 日午後 4:13
25
仕様はまだドラフト段階 であるため、現時点での実装は予定していません。あなたが挙げた Mozilla のウェブサイトにも以下のように記載されています。
Feature-Policy ヘッダーは現在実験的な段階にあり、いつでも変更される可能性があります。Web サイトで Feature Policy を実装する際は、この点に注意してください。
「いいね!」 8
riking
(Kane York)
2020 年 6 月 2 日午後 4:20
26
adrelanos:
vibrate ‘none’;
vibrate 'self' - Androidでの「いいね」は、かすく短い振動をトリガーします。
「いいね!」 10
R_X
2020 年 8 月 13 日午前 8:15
29
Discourse 2.6.0.beta1 をインストールしました。再設定は必要でしょうか?よろしくお願いいたします。
「いいね!」 1
jomaxro
(Joshua Rosenfeld)
2020 年 8 月 13 日午後 2:58
30
必要ありません。これはデフォルトでオンになっています。外部リソースがブロックされているのを見て、それを実行させたい場合のみ、設定を変更する必要があります。
「いいね!」 4
2.6.0 ベータ 2 を実行しています。
フォーラムで以下のサービスを使用しています:
Google Tag Manager
Google Ad Manager
Google Ad Sense
現在、すべての未解決の問題を解決するまでの間、CSP をレポートモードのみに設定しています。
私の CSP 設定は以下の通りです:
現在の設定でも、依然として CSP エラーが大量に発生しています。いくつかは無視できるもののように見えます。しかし、CSP 設定にドメインを宣言しているにもかかわらず、このエラーは私を困惑させています。
何か見落としているのでしょうか?
CSP Violation: 'https://www.googletagmanager.com/gtm.js?id=GTM-T9ZW6PR'
バックトレース:
/var/www/discourse/app/controllers/csp_reports_controller.rb:9:in `create'
actionpack-6.0.3.2/lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
actionpack-6.0.3.2/lib/abstract_controller/base.rb:195:in `process_action'
actionpack-6.0.3.2/lib/action_controller/metal/rendering.rb:30:in `process_action'
actionpack-6.0.3.2/lib/abstract_controller/callbacks.rb:42:in `block in process_action'
activesupport-6.0.3.2/lib/active_support/callbacks.rb:112:in `block in run_callbacks'
/var/www/discourse/app/controllers/application_controller.rb:340:in `block in with_resolved_locale'
i18n-1.8.5/lib/i18n.rb:313:in `with_locale'
/var/www/discourse/app/controllers/application_controller.rb:340:in `with_resolved_locale'
activesupport-6.0.3.2/lib/active_support/callbacks.rb:121:in `block in run_callbacks'
activesupport-6.0.3.2/lib/active_support/callbacks.rb:139:in `run_callbacks'
actionpack-6.0.3.2/lib/abstract_controller/callbacks.rb:41:in `process_action'
actionpack-6.0.3.2/lib/action_controller/metal/rescue.rb:22:in `process_action'
actionpack-6.0.3.2/lib/action_controller/metal/instrumentation.rb:33:in `block in process_action'
activesupport-6.0.3.2/lib/active_support/notifications.rb:180:in `block in instrument'
activesupport-6.0.3.2/lib/active_support/notifications/instrumenter.rb:24:in `instrument'
activesupport-6.0.3.2/lib/active_support/notifications.rb:180:in `instrument'
actionpack-6.0.3.2/lib/action_controller/metal/instrumentation.rb:32:in `process_action'
actionpack-6.0.3.2/lib/action_controller/metal/params_wrapper.rb:245:in `process_action'
activerecord-6.0.3.2/lib/active_record/railties/controller_runtime.rb:27:in `process_action'
actionpack-6.0.3.2/lib/abstract_controller/base.rb:136:in `process'
actionview-6.0.3.2/lib/action_view/rendering.rb:39:in `process'
rack-mini-profiler-2.0.4/lib/mini_profiler/profiling_methods.rb:78:in `block in profile_method'
actionpack-6.0.3.2/lib/action_controller/metal.rb:190:in `dispatch'
actionpack-6.0.3.2/lib/action_controller/metal.rb:254:in `dispatch'
actionpack-6.0.3.2/lib/action_dispatch/routing/route_set.rb:50:in `dispatch'
actionpack-6.0.3.2/lib/action_dispatch/routing/route_set.rb:33:in `serve'
actionpack-6.0.3.2/lib/action_dispatch/journey/router.rb:49:in `block in serve'
actionpack-6.0.3.2/lib/action_dispatch/journey/router.rb:32:in `each'
actionpack-6.0.3.2/lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack-6.0.3.2/lib/action_dispatch/routing/route_set.rb:834:in `call'
/var/www/discourse/lib/middleware/omniauth_bypass_middleware.rb:68:in `call'
rack-2.2.3/lib/rack/tempfile_reaper.rb:15:in `call'
rack-2.2.3/lib/rack/conditional_get.rb:40:in `call'
rack-2.2.3/lib/rack/head.rb:12:in `call'
/var/www/discourse/lib/content_security_policy/middleware.rb:12:in `call'
/var/www/discourse/lib/middleware/anonymous_cache.rb:336:in `call'
rack-2.2.3/lib/rack/session/abstract/id.rb:266:in `context'
rack-2.2.3/lib/rack/session/abstract/id.rb:260:in `call'
actionpack-6.0.3.2/lib/action_dispatch/middleware/cookies.rb:648:in `call'
actionpack-6.0.3.2/lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport-6.0.3.2/lib/active_support/callbacks.rb:101:in `run_callbacks'
actionpack-6.0.3.2/lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack-6.0.3.2/lib/action_dispatch/middleware/actionable_exceptions.rb:17:in `call'
actionpack-6.0.3.2/lib/action_dispatch/middleware/debug_exceptions.rb:32:in `call'
actionpack-6.0.3.2/lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
logster-2.9.3/lib/logster/middleware/reporter.rb:43:in `call'
railties-6.0.3.2/lib/rails/rack/logger.rb:37:in `call_app'
railties-6.0.3.2/lib/rails/rack/logger.rb:28:in `call'
/var/www/discourse/config/initializers/100-quiet_logger.rb:19:in `call'
/var/www/discourse/config/initializers/100-silence_logger.rb:31:in `call'
actionpack-6.0.3.2/lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
actionpack-6.0.3.2/lib/action_dispatch/middleware/request_id.rb:27:in `call'
/var/www/discourse/lib/middleware/enforce_hostname.rb:22:in `call'
rack-2.2.3/lib/rack/method_override.rb:24:in `call'
actionpack-6.0.3.2/lib/action_dispatch/middleware/executor.rb:14:in `call'
rack-2.2.3/lib/rack/sendfile.rb:110:in `call'
actionpack-6.0.3.2/lib/action_dispatch/middleware/host_authorization.rb:76:in `call'
rack-mini-profiler-2.0.4/lib/mini_profiler/profiler.rb:200:in `call'
message_bus-3.3.1/lib/message_bus/rack/middleware.rb:61:in `call'
/var/www/discourse/lib/middleware/request_tracker.rb:176:in `call'
railties-6.0.3.2/lib/rails/engine.rb:527:in `call'
railties-6.0.3.2/lib/rails/railtie.rb:190:in `public_send'
railties-6.0.3.2/lib/rails/railtie.rb:190:in `method_missing'
rack-2.2.3/lib/rack/urlmap.rb:74:in `block in call'
rack-2.2.3/lib/rack/urlmap.rb:58:in `each'
rack-2.2.3/lib/rack/urlmap.rb:58:in `call'
unicorn-5.6.0/lib/unicorn/http_server.rb:632:in `process_client'
unicorn-5.6.0/lib/unicorn/http_server.rb:728:in `worker_loop'
unicorn-5.6.0/lib/unicorn/http_server.rb:548:in `spawn_missing_workers'
unicorn-5.6.0/lib/unicorn/http_server.rb:144:in `start'
unicorn-5.6.0/bin/unicorn:128:in `<top (required)>'
/var/www/discourse/vendor/bundle/ruby/2.6.0/bin/unicorn:23:in `load'
/var/www/discourse/vendor/bundle/ruby/2.6.0/bin/unicorn:23:in `<main>'
Env 1:
hostname forums-web-only
process_id 27127
application_version f2e14a3946b020ace5a368614f0da198cd17aa32
HTTP_HOST forums.paddling.com
REQUEST_URI /csp_reports
REQUEST_METHOD POST
HTTP_USER_AGENT Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:80.0) Gecko/20100101 Firefox/80.0
HTTP_ACCEPT */*
HTTP_X_FORWARDED_FOR 74.76.45.218
HTTP_X_REAL_IP 74.76.45.218
time 1:44 pm
Env 2:
hostname forums-web-only
process_id 27161
application_version f2e14a3946b020ace5a368614f0da198cd17aa32
HTTP_HOST forums.paddling.com
REQUEST_URI /csp_reports
REQUEST_METHOD POST
HTTP_USER_AGENT Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0
HTTP_ACCEPT */*
HTTP_X_FORWARDED_FOR 66.58.144.146
HTTP_X_REAL_IP 66.58.144.146
time 1:39 pm
Env 3:
hostname forums-web-only
process_id 27111
application_version f2e14a3946b020ace5a368614f0da198cd17aa32
HTTP_HOST forums.paddling.com
REQUEST_URI /csp_reports
REQUEST_METHOD POST
HTTP_USER_AGENT Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
HTTP_ACCEPT */*
HTTP_REFERER https://forums.paddling.com/t/need-advice-loading-a-kayak-onto-j-rac/60058
HTTP_X_FORWARDED_FOR 174.83.24.11
HTTP_X_REAL_IP 174.83.24.11
time 12:16 pm
「いいね!」 2
pmusaraj
(Penar Musaraj)
2020 年 9 月 2 日午後 6:19
32
CSP のレポートには、誤検知が非常に多く含まれています。詳細については、私の 上記の返信 をご覧ください。
スクリーンショットで設定されているルールのほとんどは不要です。https: と unsafe-inline のみで十分です。これらは https で始まるすべてのスクリプトと、すべてのインラインスクリプトを許可します。CSP ソース設定を整理し、CSP(レポート機能なし)を有効にしてみてください。これで動作するはずです。
「いいね!」 8
こんにちは、ご質問ありがとうございます。Content-Security-Policy: frame-ancestors ‘none’ ディレクティブは、元の投稿者(OP)が言及した「今後のアップデートに含まれる予定のもの」でしょうか?
このディレクティブを何らかの方法で追加することは可能でしょうか、それとも待つべきでしょうか?セキュリティ強化の作業を行っていたところ、このオンラインセキュリティツールから唯一の未対応項目(推奨事項)として指摘されました。プラットフォームに対する信頼がさらに高まりました。素晴らしい仕事をありがとうございます!
「いいね!」 5
よくわからないけど、どう思う? @xrav3nz ?
「いいね!」 4
今は気にしなくて大丈夫だと思います。
frame-ancestors は、Discourse/Rails が既に強制している X-Frame-Options ヘッダー に似ています。現在、このヘッダーは sameorigin に設定されており、これは CSP ディレクティブの self オプションとほぼ同じです。
個人的には、self 以外の特定のドメインをホワイトリストに登録する必要がある場合を除き、現時点で frame-ancestors を実装してもあまりメリットはないと思います。
「いいね!」 8
neounix
(Dark Matter)
2021 年 1 月 4 日午前 4:57
36
これに賛成です。
考えられるすべての脆弱性スキャナーの「問題」を追いかけることは、リスクとベネフィットの比率が非常に低いにもかかわらず、重要な機能を壊す結果になりかねません。
理論上は脆弱性として存在するが、実際にはほとんど悪用されない、あるいは極めて特定の状況下でのみ悪用可能な「脆弱性」が多数存在します。私の知る限り、このような潜在的な脆弱性が Discourse サイトで実際に悪用された例はありません。したがって、「理論上は脆弱性」であり、かつ重大な侵害を引き起こしたことがないものを「修正」しようとするのはお勧めしません。
これは数十年のサイバーセキュリティ専門家としての私の意見です。もしご関心があれば、サイバーセキュリティのリスク管理の基礎について喜んで議論します。
「いいね!」 5
Falco
(Falco)
2021 年 3 月 23 日午前 12:11
37
CSP の frame-ancestors ディレクティブのサポートを追加しました。現時点では、content security policy frame ancestors サイト設定の背後で無効化されています。ドメインの追加は、いつも通り /admin/customize/embedding から行ってください。
このディレクティブは、次のリリースサイクルでデフォルトで有効になります。
「いいね!」 7