offline / laravel-csp
为 Laravel 应用的响应添加 CSP 头部 (Fork)
Requires
- php: >=7.1
- illuminate/support: ~5.5.0|~6.0|~9.0
This package is auto-updated.
Last update: 2024-09-04 20:09:16 UTC
README
默认情况下,网页上的所有脚本都被允许向任何网站发送和获取数据。这可能会导致安全问题。想象一下,你的 JavaScript 依赖项将所有按键,包括密码,发送到第三方网站。
有人很容易隐藏这种恶意行为,让你几乎无法检测到它(除非你手动阅读你网站上所有的 JavaScript 代码)。为了更好地了解为什么你需要设置内容安全策略头部,请阅读 David Gilbertson 的这篇优秀的博客文章:https://hackernoon.com/im-harvesting-credit-card-numbers-and-passwords-from-your-site-here-s-how-9a8cb347c5b5。
设置内容安全策略头部有助于解决这个问题。这些头部指定了哪些网站可以与你的网站进行通信。这个包让你可以轻松地设置正确的头部。
本说明文档的目的不是全面解释 CSP 和其指令的所有可能用法。我们强烈建议你在使用此包之前阅读 Mozilla 的内容安全策略文档。
如果你是一个视听学习者,你应该看看这个关于如何使用此包的视频。 https://www.laraning.com/videos/OFFLINE-csp-content-security-policy
支持我们
我们投入了大量资源来创建 一流的开放源代码包。你可以通过 购买我们的付费产品之一 来支持我们。
我们非常感谢你从家乡寄给我们明信片,提到你正在使用我们哪些包。你可以在 我们的联系页面 上找到我们的地址。我们将发布所有收到的明信片在 我们的虚拟明信片墙上。
安装
您可以通过 composer 安装此包
composer require OFFLINE/laravel-csp
您可以使用以下命令发布配置文件
php artisan vendor:publish --provider="OFFLINE\LaravelCSP\CspServiceProvider" --tag="config"
此文件的内容将发布在 config/csp.php 中
return [ /* * A policy will determine which CSP headers will be set. A valid CSP policy is * any class that extends `OFFLINE\LaravelCSP\Policies\Policy` */ 'policy' => OFFLINE\LaravelCSP\Policies\Basic::class, /* * This policy which will be put in report only mode. This is great for testing out * a new policy or changes to existing csp policy without breaking anything. */ 'report_only_policy' => '', /* * All violations against the policy will be reported to this url. * A great service you could use for this is https://report-uri.com/ * * You can override this setting by calling `reportTo` on your policy. */ 'report_uri' => env('CSP_REPORT_URI', ''), /* * Headers will only be added if this setting is set to true. */ 'enabled' => env('CSP_ENABLED', true), /* * The class responsible for generating the nonces used in inline tags and headers. */ 'nonce_generator' => OFFLINE\LaravelCSP\Nonce\RandomString::class, ];
您可以通过在 http kernel 中注册 OFFLINE\LaravelCSP\AddCspHeaders::class 来将 CSP 头部添加到您应用程序的所有响应中。
// app/Http/Kernel.php ... protected $middlewareGroups = [ 'web' => [ ... \OFFLINE\LaravelCSP\AddCspHeaders::class, ],
或者,您也可以在路由或路由组级别应用中间件。
// in a routes file Route::get('my-page', 'MyController')->middleware(OFFLINE\LaravelCSP\AddCspHeaders::class);
您还可以将策略类作为参数传递给中间件
// in a routes file Route::get('my-page', 'MyController')->middleware(OFFLINE\LaravelCSP\AddCspHeaders::class . ':' . MyPolicy::class);
给定的策略将覆盖配置文件中为该特定路由或路由组配置的策略。
用法
此包允许您定义 CSP 策略。CSP 策略决定了将在响应头中设置的哪些 CSP 指令。
CSP 指令的一个例子是 script-src。如果此处的值为 'self' www.google.com,则您的网站只能从它自己的域名或 www.google.com 加载脚本。您可以在 Mozilla 优秀的开发者网站上找到 所有 CSP 指令的列表。
根据规范,某些指令值需要用引号包围。例如,有 'self'、'none' 和 'unsafe-inline'。当使用 addDirective 函数时,您不需要手动用引号包围指令值。我们将自动添加引号。脚本/样式哈希也将自动检测并用引号包围。
// in a policy ... ->addDirective(Directive::SCRIPT, Keyword::SELF) // will output `'self'` when outputting headers ->addDirective(Directive::STYLE, 'sha256-hash') // will output `'sha256-hash'` when outputting headers ...
您可以在同一个指令中添加多个策略选项,将数组作为 addDirective 的第二个参数,或者将每个选项通过一个或多个空格分隔的单个字符串。
// in a policy ... ->addDirective(Directive::SCRIPT, [ Keyword::STRICT_DYNAMIC, Keyword::SELF, 'www.google.com', ]) ->addDirective(Directive::SCRIPT, 'strict-dynamic self www.google.com') // will both output `'strict_dynamic' 'self' www.google.com` when outputting headers ...
也有一些情况下,您不需要或不需要指定值,例如 upgrade-insecure-requests、block-all-mixed-content 等。在这种情况下,您可以使用以下值
// in a policy ... ->addDirective(Directive::UPGRADE_INSECURE_REQUESTS, Value::NO_VALUE) ->addDirective(Directive::BLOCK_ALL_MIXED_CONTENT, Value::NO_VALUE); ...
这将输出类似以下内容的 CSP
Content-Security-Policy: upgrade-insecure-requests;block-all-mixed-content
创建策略
在 csp 配置文件的 policy 键默认设置为 \OFFLINE\LaravelCSP\Policies\Basic::class。这个类允许您的网站仅使用自己的图像、脚本和表单操作。这个类看起来是这样的。
namespace OFFLINE\LaravelCSP\Policies; use OFFLINE\LaravelCSP\Directive; use OFFLINE\LaravelCSP\Value; class Basic extends Policy { public function configure() { $this ->addDirective(Directive::BASE, Keyword::SELF) ->addDirective(Directive::CONNECT, Keyword::SELF) ->addDirective(Directive::DEFAULT, Keyword::SELF) ->addDirective(Directive::FORM_ACTION, Keyword::SELF) ->addDirective(Directive::IMG, Keyword::SELF) ->addDirective(Directive::MEDIA, Keyword::SELF) ->addDirective(Directive::OBJECT, Keyword::NONE) ->addDirective(Directive::SCRIPT, Keyword::SELF) ->addDirective(Directive::STYLE, Keyword::SELF) ->addNonceForDirective(Directive::SCRIPT) ->addNonceForDirective(Directive::STYLE); } }
您可以通过扩展这个类来允许从 www.google.com 获取脚本
namespace App\Services\Csp\Policies; use OFFLINE\LaravelCSP\Directive; use OFFLINE\LaravelCSP\Policies\Basic; class MyCustomPolicy extends Basic { public function configure() { parent::configure(); $this->addDirective(Directive::SCRIPT, 'www.google.com'); } }
别忘了在 csp 配置文件中将 policy 键设置为策略类的名称(在这种情况下将是 App\Services\Csp\Policies\MyCustomPolicy)。
使用内联脚本和样式
当使用 CSP 时,您必须明确允许使用内联脚本或样式。使用此包推荐的方法是使用一个 nonce。nonce 是每个请求都是唯一的数字。nonce 必须在 CSP 标题和 HTML 标签上的属性中指定。这样,攻击者就没有注入恶意脚本或样式的途径。
首先,您必须将 nonce 添加到策略中的正确指令
// in a policy public function configure() { $this ->addDirective(Directive::SCRIPT, 'self') ->addDirective(Directive::STYLE, 'self') ->addNonceForDirective(Directive::SCRIPT) ->addNonceForDirective(Directive::STYLE) ... }
接下来,您必须将 nonce 添加到 HTML 中
{{-- in a view --}}
<style nonce="{{ csp_nonce() }}">
...
</style>
<script nonce="{{ csp_nonce() }}">
...
</script>
还有其他一些选项可以用于内联样式和脚本。请参阅 Mozilla 开发者网站上关于 CSP 的文档 了解更多。
报告 CSP 错误
在浏览器中
您可以将策略设置为仅报告模式,而不是直接阻止所有违规行为。在这种情况下,所有请求都将被发出,但所有违规行为都将显示在您喜欢的浏览器的控制台中。
要将策略设置为仅报告模式,只需在报告的 configure() 函数中调用 reportOnly()
public function configure() { parent::configure(); $this->reportOnly(); }
到外部 URL
任何违反策略的行为都可以报告给指定的 URL。您可以在 csp 配置文件的 report_uri 键中设置该 URL。一个专为处理这些违规报告而构建的出色服务是 http://report-uri.io/。
使用多个策略
要测试对您的 CSP 策略的更改,您可以在 csp 配置键的 report_only_policy 中指定第二个策略。指定的 policy 将被强制执行,而 report_only_policy 中的策略则不会。这对于在不破坏任何内容的情况下测试新策略或现有 CSP 策略的更改非常有用。
使用 whoops
Laravel 附带 whoops,这是一个错误处理框架,它通过异常的精美可视化帮助您调试应用程序。Whoops 使用内联脚本和样式,因为它无法对其被使用的环境做出任何假设,因此除非您为脚本和样式允许 unsafe-inline,否则它将不起作用。
解决此问题的一个方法是在设置策略时检查config('app.debug')。遗憾的是,这存在忘记在所有CSP规则启用的情况下测试你的代码,导致应用程序在部署时崩溃的风险。作为替代方案,你可以在异常处理器的render方法中添加以下内容,仅将unsafe-inline允许在错误页面上:
$this->container->singleton(AppPolicy::class, function ($app) { return new AppPolicy(); }); app(AppPolicy::class)->addDirective(Directive::SCRIPT, Keyword::UNSAFE_INLINE); app(AppPolicy::class)->addDirective(Directive::STYLE, Keyword::UNSAFE_INLINE);
其中AppPolicy是您的CSP策略名称。在所有其他情况下,这也可以在运行时更改策略,在这种情况下,应该在服务提供程序而不是异常处理器中执行单例注册。
请注意,unsafe-inline仅在您没有发送nonce或strict-dynamic指令时才有效,因此要能够使用此解决方案,您必须在CSP标题中指定所有内联脚本和样式的哈希值。
测试
您可以使用以下命令运行所有测试:
composer test
变更日志
有关最近更改的更多信息,请参阅变更日志。
贡献
有关详细信息,请参阅贡献指南。
安全性
如果您发现任何与安全相关的问题,请通过电子邮件freek@OFFLINE.be而不是使用问题跟踪器。
鸣谢
许可证
MIT许可证(MIT)。有关更多信息,请参阅许可证文件。