-
Notifications
You must be signed in to change notification settings - Fork 20
Getting Started
Before the real introduction, the following should be taken as a good implementation examples (SecureHeaders will tell you if you're missing policies, or if they look questionable).
These aren't good because they're short, rather they make use of some key browser security features (namely HSTS and CSP)
$headers = new SecureHeaders();
$headers->hsts();
$headers->csp('default', 'self');
$headers->csp('script', 'https://my.cdn.org');
$headers->apply();
Here's an even better one (but don't copy paste it into production code unless you understand what HSTS preloading is):
$headers = new SecureHeaders();
$headers->strictMode();
$headers->cspNonce('script');
$headers->apply();
As an aside to that warning, do take a look at ->safeMode
if you're worried about breaking something with headers (or don't plan on reading the documentation before typing).
For more on these examples, see below.
To get started with SecureHeaders, you need only create an instance of the class and call ->apply
before your first byte of output. If you're not sure where, or what that is then you can tell SecureHeaders to set all the headers for you when output is generated, using ->applyOnOutput
.
The former option is simply the following two lines of code:
$headers = new SecureHeaders();
$headers->apply();
The latter could be achieved by slightly rewriting the second line.
Okay, so what did that do exactly?
The following details behaviour that is automatically applied to every instance of SecureHeaders (unless these settings are modified).
When ->apply
was called, SecureHeaders analysed all the headers already loaded in PHPs internal list.
As part of this process, the following headers will be sent. This provided they don't already have values (and are not explicitly removed using ->removeHeader
).
Expect-CT: max-age=0
Referrer-Policy: no-referrer
Referrer-Policy: strict-origin-when-cross-origin
X-Content-Type-Options:nosniff
X-Frame-Options:Deny
X-Permitted-Cross-Domain-Policies: none
X-XSS-Protection:1; mode=block
SecureHeaders will also note that neither a Content-Security-Policy has been defined, nor an HSTS policy. The following warnings will be generated as a result of this:
Warning: Missing security header: 'Strict-Transport-Security'
Warning: Missing security header: 'Content-Security-Policy'
Additionally, some headers will be removed. In particular the header X-Powered-By
(often sent by default) will be removed by SecureHeaders. This header is removed because it often leaks quite detailed version information about the current PHP installation. While certainly not a vulnerability itself, this header can aid an attacker in profiling the system (let's not give out this information for free).
It is also advisable that the Server
header is removed, because it leaks much of the same information. SecureHeaders will attempt to remove it. However, it is unlikely PHP will be able to affect this header if the underlying web server is sending it. So this header should be configured manually in the web server.
If any cookies have been set at any time before ->apply()
is
called(, or at any time before the first byte of output if ->applyOnOutput()
is set).
Consider the following as an example.
<?php
$headers = new SecureHeaders();
$headers->applyOnOutput();
setcookie('auth', generateSuperSecretAuthenticationString());
?>
<html>
<body>
<h1>Account Settings</h1>
...
</body>
</html>
Even though in the current PHP configuration, cookie flags Secure
and
HTTPOnly
do not default to on, and despite the fact that
PHP does not support the SameSite
cookie attribute, the end result of the
Set-Cookie
header will be
Set-Cookie:auth=supersecretauthenticationstring; Secure; HttpOnly; SameSite=Lax
These flags were inserted by SecureHeaders because the cookie name contained the substring auth
. Of course if that was a bad assumption, you can correct SecureHeaders' behaviour (->protectedCookie
), conversely you can tell SecureHeaders about some of your cookies that have less obvious names – but may need protecting in case of accidental missing flags.
There's quite a bit more to cover: CSP, HSTS, HPKP, and much more – just check out the sidebar and have a browse through the function list to take a look.
To cover the initial examples in a bit more detail:
$headers = new SecureHeaders();
$headers->hsts();
$headers->csp('default', 'self');
$headers->csp('script', 'https://my.cdn.org');
$headers->apply();
Here, ->hsts
with no arguments will deploy Strict-Transport-Security with a one year duration.
The lines calling ->csp
will add 'self'
as a whitelisted source to default-src
(note the use of friendly directive, and friendly source names here to save a little typing).
$headers = new SecureHeaders();
$headers->strictMode();
$headers->cspNonce('script');
$headers->apply();
Here, ->strictMode
is used. Strict mode will deploy Strict-Transport-Security with a one year duration, and includeSubDomains
and preload
flags. (You'll still have to manually submit your domain to become preloaded though).
Strict mode will also opportunistically enable 'strict-dynamic'
in CSP – which disables the whitelist in CSP3 compliant browsers for the script-src
directive in favour of hashes and nonces.
The line calling ->cspNonce
simply generates a nonce for the script-src
directive. Note that this nonce can be retrieved at any time by calling the same function with script-src
, or one of its friendly names (as above). By default ->cspNonce
will only generate a new nonce for the directive if one does not already exist, and will always return a nonce for the directive specified (whether it be newly generated, or an already existing nonce).