How to configure security headers for Laravel

Some time ago I read an excellent article by Scott Helme on security headers. If you want to learn more about these headers I suggest you read the article yourself.

I've added security headers to this website and want to show you how it was done.

Step 1: Security headers for Laravel

I've used the bepsvpt/laravel-security-header package for adding security headers. It supports all the main headers plus some extra.

The configuration file is full of links to websites with more information. My current configuration looks like this:

<?php

$protocol = 'https://';
if (! isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] == 'off') {
    $protocol = 'http://';
}

return [
    'x-content-type-options' => 'nosniff',
    'x-download-options' => 'noopen',
    'x-frame-options' => 'sameorigin',
    'x-permitted-cross-domain-policies' => 'none',
    'x-xss-protection' => '1; mode=block',
    'referrer-policy' => 'unsafe-url',
    'hsts' => [
        'enable' => env('SECURITY_HEADER_HSTS_ENABLE', false),
        'max-age' => 31536000,
        'include-sub-domains' => true,
    ],
    'hpkp' => [
        'hashes' => false,
        'include-sub-domains' => false,
        'max-age' => 15552000,
        'report-only' => false,
        'report-uri' => null,
    ],
    'custom-csp' => env('SECURITY_HEADER_CUSTOM_CSP', null),
    'csp' => [
        'report-only' => false,
        'report-uri' => env('CONTENT_SECURITY_POLICY_REPORT_URI', false),
        'upgrade-insecure-requests' => false,
        'default-src' => [
            'self' => true,
        ],
        'script-src' => [
            'allow' => [
                $protocol.'ajax.googleapis.com',
                $protocol.'code.jquery.com',
                $protocol.'www.googletagmanager.com',
                $protocol.'www.google-analytics.com',
            ],
            'self' => true,
            'unsafe-inline' => true,
            'unsafe-eval' => true,
            'data' => true,
        ],
        'style-src' => [
            'allow' => [
                $protocol.'fonts.googleapis.com',
            ],
            'self' => true,
            'unsafe-inline' => true,
        ],
        'img-src' => [
            'allow' => [
                $protocol.'www.google-analytics.com',
            ],
            'self' => true,
            'data' => true,
        ],
        'font-src' => [
            'allow' => [
                $protocol.'fonts.gstatic.com',
            ],
            'self' => true,
            'data' => true,
        ],
        'object-src' => [
            'allow' => [],
            'self' => false,
        ],
    ],
];

Some notes:

  • Only enable Strict-Transport-Security if you have an SSL certificate. And then you probably only want to enable it on your production environment.
  • Have a look at paragonie/csp-builder for configuring the Content-Security-Policy header. This is a dependency used by bepsvpt/laravel-security-header.
  • HTTP Public Key Pinning sounds a bit scary, mistakes are probably difficult to solve. I'm no expert in SSL keys or CSR so I haven't enabled this header.

Step 2: Test your setup

Test your headers in your browser. You will have to tweak the CSP a bit, enable stuff like Google Analytics or widgets.

After that, scan your website at securityheaders.io, another project by Scott Helme. It will scan your headers and give some advice on stuff you can improve.

Step 3: Configure a report URI

If a browser encounters content that is violating the Content Security Policy it can report this. The URI that is reported to can be configured in the CSP header itself.

A great (and free) service that you use for this is report-uri.com. Again, this is made by Scott Helme, this is getting awkward... After setting up your personal report-uri you can see reports for content that violated your CSP. Below is the report for this website for last month:

Report-uri.io report
Report-uri.io report

Do you have a good tip on using security headers? Please share your thoughts! Having trouble using these instructions? Don't be afraid to ask!

Related articles

Comments (10)

Got a question? Liked the article or got a suggestion? Leave a comment to let us know.

Thanks for the article.
But wouldn't it be better to set the headers in the .htaccess so they are served for all files? Plus performance will be better.
Hi Michael,

I don't think it makes a real difference since most headers are primarily needed for the HTML document you are serving. For me, serving the headers through PHP is fine and allows me to configure it differently for my development en production environment.

Here's a blog that configures the same headers with a .htaccess file: https://danielnixon.org/http-security-headers/.
Thanks for a great article!

I have some issues though. I get the following error:

VM2260:1 Refused to connect to 'https://l.sharethis.com/pview?event=pview&version=st_insights.js&lang=en&fpc=1234&sessionID=1234&hostname=myhost.com&location=%2F&product=inline-share-buttons&publisher=etc' because it violates the following Content Security Policy directive: "connect-src ".

I have tried adding it to the connect-src attribute like so:

'connect-src' => [
'l.sharethis.com',
'https://l.sharethis.com/',
'https://l.sharethis.com'
],

But it does not work. What can I do?
Hi Mattias,

It looks all right to me. Maybe you should clear the cache with "php artisan config:cache"?

Good luck!

Barry
This is what I love about Laravel, it has some really good packages for improving the security of Laravel based apps. For example, you have package for removing XSS vulnerabilities. You also have package for protecting routes and CRUD controller methods. Source, Laravel security (https://www.cloudways.com/blog/best-laravel-security-practices/ )
This is a great article, thank you! Hey I have been crazy for this problem, Hopefully you can help me. I have the same configuration of your example BUT I get this message in firefox "Content Security Policy: The page’s settings blocked the loading of a resource at data:image/svg+xml;base64,PHN2ZyB2aWV3Qm… (“img-src”)." and I can not fix on the secure-header.php file, do you know how to allow a .svg on that file?

Thank you in advance Barry.
Hi Wilbert, you should probably add something to the img-src directive that is similar to "img-src 'self' data:". The "data:" part is the important bit. If you already did this then I wouldn't know without looking at some code.

Hope this helps, good luck!
Hi, I have tried installing this package but my site is broken after I installed it. What will be the reason?
I though might be my site reason so I try fresh installation of laravel V6.9 and install this package but still the page is home page is broken.
Tried " php artisan config:cache", "composer dump-autoload" still the same.
How can I fix the broken site issue?

I wish there is more documentation on how to use it.
Hi Jaikangam,

Sorry to hear you have problems but "my site is broken" is not enough information to help you. Have you tried opening the console of your browser and see whether there are any error messages there? In my experience the Chrome devtools console gives some very helpful output when you broke any CSP rules.

Good luck!

Barry