Once a webpage leaves your servers, anything can happen to it. Sometimes, the client’s browser tries to execute scripts against your page that range from the benign changing of font colors to nastier XSS attacks that manipulate and steal user data.
This is where a Content Security Policy comes into play. It basically instructs the browser what kinds of content is allowed to load for your site. This includes restricting loading of external scripts, images and any other files that might want to load on top of your page.
Implementing this is quite easy in Laravel:
composer require spatie/laravel-csp
php artisan vendor:publish --provider="Spatie\Csp\CspServiceProvider" --tag="config"
- Then, add it to your middleware in
app/Http/Kernel.php
:
protected $middlewareGroups = [
'web' => [
\Spatie\Csp\AddCspHeaders::class,
// other middlewares
],
];
Your CSP is set up! You can view the directives in vendor/spatie/laravel-csp/src/Policies/Basic.php
. This is a bit restrictive though, so you might want to publish your own policy instead. Here’s one I used recently:
<?php
namespace App\Services\Csp\Policies;
use Spatie\Csp\Policies\Policy;
use Spatie\Csp\Directive;
use Spatie\Csp\Keyword;
class MyPolicies extends Policy
{
public function configure()
{
$this
->addDirective(Directive::BASE, Keyword::SELF)
->addDirective(Directive::CONNECT, Keyword::SELF)
->addDirective(Directive::FORM_ACTION, Keyword::SELF)
->addDirective(Directive::IMG, [
Keyword::SELF,
'data:',
'blob:'
])
->addDirective(Directive::MEDIA, Keyword::SELF)
->addDirective(Directive::SCRIPT, [
Keyword::SELF,
'www.google.com',
'www.gstatic.com'
])
->addDirective(Directive::OBJECT, Keyword::NONE);
}
}
You can learn about what the different policy directives mean in the Content Security Policy Quick Reference Guide. In my own policy above, I allowed image blobs and base 64 image data, as well as letting Google in because of Recaptcha and Analytics.
- Create your new policy. I saved mine in
app/Services/Csp/Policies/MyPolicies.php
. Feel free to use my own policy above as a starting point for your own. - Go to
config/csp.php
- Replace the content so that it will use your new policy instead
<?php
use App\Services\Csp\Policies\MyPolicies;
return [
/*
* A policy will determine which CSP headers will be set. A valid CSP policy is
* any class that extends `Spatie\Csp\Policies\Policy`
*/
// replace the default policy
//'policy' => Spatie\Csp\Policies\Basic::class,
'policy' => MyPolicies::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' => Spatie\Csp\Nonce\RandomString::class,
];
Now that you have your CSP set up, you can check it by entering your site in Google’s CSP Evaluator. Mine showed this:
Of course, this is just a guide, no need to be alarmed if it says high severity. For me, the script-src finding was okay because I needed to allow Google scripts to run on the site. So evaluate your results based on how your webapp works and don’t force your site to get all green checks in this test.
Hope to see more people securing their site via CSP!
Source: Christoph Rumpel