使用内容安全策略缓解 XSS 攻击

:bookmark: 本指南介绍如何使用内容安全策略(CSP)来缓解 Discourse 中的跨站脚本(XSS)攻击。内容涵盖 CSP 基础、配置方法及最佳实践。

:person_raising_hand: 所需用户级别:管理员

摘要

内容安全策略(CSP)是 Discourse 中一项关键的安全功能,有助于防范跨站脚本(XSS)及其他注入攻击。本指南将介绍 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:控制哪些站点可以将您的 Discourse 实例嵌入到 iframe 中
  • 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

  1. 导航至您的管理面板
  2. 进入安全设置
  3. 找到 content_security_policy 设置并确保其已启用

建议先启用 CSP 报告模式以识别任何潜在问题,然后再完全启用 CSP:

  1. 启用 content_security_policy_report_only 设置
  2. 监控浏览器控制台中的 CSP 违规报告
  3. 根据需要扩展 CSP 以解决任何合法的违规
  4. 一旦确认没有误报,请禁用报告模式并完全启用 CSP

扩展默认 CSP

如果您需要允许额外的脚本来源,可以使用 content_security_policy_script_src 设置扩展 script-src 指令。您可以添加:

  • 哈希来源
  • 'wasm-unsafe-eval'
  • 'unsafe-eval'(请谨慎使用)

例如:

'sha256-QFlnYO2Ll+rgFRKkUmtyRublBc7KFNsbzF7BzoCqjgA=' 'unsafe-eval'

:warning: 添加 'unsafe-eval' 或其他宽松指令时请务必谨慎,因为它们可能会降低 CSP 的有效性。

CSP 与第三方集成

当使用 Google Tag Manager、Google Analytics 或广告服务等第三方服务时,您可能需要调整 CSP 设置。在大多数情况下,使用 Discourse 3.3.0.beta1 或更高版本时,由于实施了“严格动态”CSP,外部脚本无需额外配置即可正常工作。

如果您遇到问题,可能需要:

  1. 通过监控浏览器控制台识别所需的脚本来源
  2. 将必要的来源添加到 content_security_policy_script_src 设置中
  3. 对于像广告服务这样加载外部资源的复杂集成,您可能需要启用跨域渲染(参考 discourse-adplugin 的相关 PR 示例)。

最佳实践

  1. 从 CSP 报告模式开始,以识别潜在问题
  2. 在解决合法违规后,逐步收紧 CSP
  3. 定期审查 CSP 设置并根据需要进行调整
  4. 添加 'unsafe-eval''wasm-unsafe-eval' 等宽松指令时请谨慎
  5. 保持 Discourse 实例更新,以利用最新的 CSP 改进

常见问题解答

问:我看到了很多 CSP 违规报告。我应该担心吗?
答:许多 CSP 违规是误报,通常由浏览器扩展或其他无关脚本引起。请重点关注与站点功能相关的违规。

问:我可以在 CSP 中使用 Google AdSense 或其他广告网络吗?
答:可以,但您可能需要使用更宽松的 CSP 设置。建议从报告模式开始,并根据报告的违规情况调整设置。

问:如何排查 CSP 问题?
答:使用浏览器的开发者工具监控控制台中的 CSP 违规消息。这将帮助您识别哪些资源被阻止以及原因。

其他资源

56 个赞
Adsense Not Working after Recent Discourse Update
Discourse 2.2.0.beta6 Release Notes
Adding statcounter code
How to restart Discourse after server reboot?
How to install npm packages in custom themes/plugins
Interactive SVG using <object>?
Video Upload to YouTube and Vimeo using Theme Component
Embed HTML5 player for MP3 file
2.5.0.beta5 breaks retort plugin
Should I load third-party libraries from vendor or cdn?
Word Cloud plugin
Embed widget within text in a topic
Discourse Intercom (Advanced)
"Unsafe JavaScript attempt to initiate navigation"
Google Tag Manager and Discourse CSP (Content Security Policy)
Cookie Consent, GDPR, and Discourse
A strange question about google ad display in my site
How to pass a component setting as a value to an attribute?
Need help integrating code wrote on Edittext to the Discourse
Issue with Activate Account Page After Update to 3.4.0 (Blank Page)
Any approved method for adding Javascript before body close?
(Superseded) Experimenting with a 'strict-dynamic' Content Security Policy (CSP)
Can't get script tag to work in landing pages plugin due to content-security-policy
How to embed Razorpay subscription button with CSP restrictions
Push custom events to Google Tag Manager and Analytics
Can I add a snippet to the header?
JS script is not loading
How do we fire scripts after topic HTML is rendered in DOM?
Iframe issue without URL
Where to place ad script?
We couldn't find the code on your site
Javascript not working in customised areas
Difficulties in correctly adding external JavaScript
Report Only CSP Violations
Nginx config in Discourse Docker?
EPN Smart Links
Discourse 2.2.0.beta9 Release Notes
"Refused to load the script" when adding adsense
Why Cookie Consent Doesn't Show Up?
[DigitalOcean] hostname having "www" in A records showing blank page
[DigitalOcean] hostname having "www" in A records showing blank page
Communities with embedded Twitter Feeds
How to add analytics and pixel scripts avoiding Content Security Policy (XSS)
When install html script facing issue?
Discourse 2.4.0.beta10 Release Notes
Add CSP sources to the plugin
IP does not redirect to domain, domain shows white page
DISCOURSE_CDN_URL causes content security policy violations?
Header content is missing due to CSP
How to insert something right after <head>?
How can I embed tracking JS into Discourse
How do I integrate ? cookiebot.com in meinen Forum?
Adding Cookie Consent Banner
Confused about remotely loaded javascript content
User input validation
Custom JS script in theme component not loading