offline / oc-csp-plugin
October CMS 的内容安全策略管理器
Requires
- php: >=7.1
- offline/laravel-csp: dev-master
README
此插件允许您通过 October 的后端管理您网站的 内容安全策略。
您应该了解 CSP 是什么以及它是如何工作的,才能使用此插件。您可以在 MDN 上 了解更多关于此主题的信息。
功能
OFFLINE.CSP
插件提供以下功能
- 可以在后端配置内容安全策略
- 在保存前预览您的 CSP
- 策略违规会自动记录,并可以在后端查看
- 为每个请求生成一个
nonce
,并可根据需要使用 - 可选地将
nonce
自动注入到所有的<script>
、<link>
和<style>
标签中 - 您的 CSP 会自动修补,以确保它不会破坏后端功能(需要
unsafe-eval
和unsafe-inline
)
入门
安装插件并访问后端设置中的 CSP 页面。根据您的需求配置 CSP。
默认情况下,已设置严格的策略。我们建议您使用此预设来优化安全性。
我们建议您从 仅报告
模式开始。这将生成 CSP 验证的每个验证的控制台消息和日志条目。
您可以通过后端设置访问日志。您将找到由您的网站生成的每个违规的日志条目。调整您的 CSP,直到不再有违规被记录。
现在,您已经准备好禁用 仅报告
模式并实际阻止违规请求。
将 CSP 作为元标签添加
如果您不想将 CSP 标头添加到每个响应中,您可以通过添加此元标签来选择某些页面
<meta http-equiv="content-security-policy" content="{{ csp_meta() }}">
请确保首先在后台设置中禁用全局响应头。请注意,使用元标签方法不支持违规报告(它们记录到浏览器控制台,但不在数据库中记录)。
测试您的 CSP
您可以使用 Google 的 CSP 验证器 或 Mozilla Observatory 来测试您 CSP 的强度。
按需使用 nonce
您可以使用 csp_nonce()
辅助函数访问当前请求的 nonce
<script nonce="{{ csp_nonce() }}"></script> <style nonce="{{ csp_nonce() }}"></style>
您可以通过后端设置启用或禁用 nonce 的自动注入。
动态修改 CSP
有时,您可能需要仅对单个页面的 CSP 配置进行更改。您可以监听 offline.csp.extend
事件并修改 CSP 设置以满足您的需求。
// Add this to your Plugin.php's boot method. \Event::listen('offline.csp.extend', function (&$settings, $controller) { // Check for a certain page. You could also use ->fileName here. if (starts_with($controller->getPage()->url, '/needs-unsafe-eval')) { // Add the unsafe-eval option to the script_src configuration. $settings['script_src'][] = 'unsafe-eval'; } });
当事情出错时
错误的 CSP 配置可能会破坏您的网站。确保在调整您的网站以符合 CSP 之前,在 仅报告
模式下工作。
如果由于任何原因您在启用 CSP 后无法访问您的网站,您可以通过运行以下控制台命令完全禁用 CSP 标头注入:
php artisan csp:disable
与十月版的Turbo路由器集成
如果您同时使用十月版的Turbo路由器和nonce,由于新的nonce属性,Turbo会将其视为新的资产,因此您的资产将包含在每次Turbo请求中。
解决这个问题的一个可能方法是,在每次请求中发送一个X-Turbo-Nonce
头部。如果该头部存在,CSP插件将回收nonce并返回带有旧nonce的新内容。
请注意,这样做会降低nonce特性的安全性,因为nonce会跨越多个请求而变得长期有效。
示例实现
将csp-nonce
元标签添加到您的head部分
<meta name="csp-nonce" content="{{ csp_nonce() }}">
监听ajax:request-start
事件,并将X-Turbo-Nonce
头部添加到每个请求中
window.addEventListener('ajax:request-start', (event: CustomEvent) => { const request = event.detail.xhr // Ignore everything not in OPENED state. if (request.readyState !== 1) { return } const nonce = document.querySelector<HTMLMetaElement>('meta[name=\'csp-nonce\']') event.detail.xhr.setRequestHeader('X-Turbo-Nonce', nonce.content) });