Showing posts with label header. Show all posts
Showing posts with label header. Show all posts

Wednesday, 8 March 2017

Response headers - adding Content-Security-Policy

I recently wrote an update as I continue to work on my response headers, in which I said that I was working on adding content-security-policy, with the help of Scott Helme, who has written a great blog post on this.  He has also created an excellent site called report-uri.io which has a number of tools, including one to help you build your CSP.

As a refresher, this is used to control what access different content on your site has.  For example, you can control what javascript and stylesheets can be included, inline or from different domains, etc.  This can help to limit the attack surface for things like cross-site scripting attacks.

So there are lots of parts, but here's how I went about it...


Default Source (default-src)

This is the default setting, so to be really secure, I went with "none".  This essentially means don't allow any content at all.  It is then overridden for each content type explicitly.

Script Source (script-src)

This is applied to all the javascript files and script tags on the page.  I started with "self", as I wanted everything from my site ("www.rik.onl") to work.  Then I looked through my code and added in the CDN domains that I was using to load the libraries I'm using... "https://code.jquery.com https://maxcdn.bootstrapcdn.com https://cdnjs.cloudflare.com" (space delimited).

Style Source (style-src)

This is applied to all stylesheet files and style tags on the page.  Again, I started with "self", and then needed to add "https://maxcdn.bootstrapcdn.com".

Image Source (image-src)

You guessed it, this is applied to all the images on the page.  This time I needed "self" and also "https://www.gravatar.com".

Font Source (font-src)

I don't load any fonts from my own site here, so I just need to add "https://maxcdn.bootstrapcdn.com".

Connect Source (connect-src)

This is applied to things like AJAX requests, web sockets and event sources.  I don't have any of these currently, so I've left this out, which means it will default to the Default Source, which is "none".  I could also explicitly set this to "none".

Media Source (media-src)

This is applied to audio and video tags.  I don't have any, so I've left this out.

Object Source (object-src)

This is applied to object, applet and embed tags.  I don't have any, so I've left this out.

Child Source (child-src) and Frame Source (frame-src - deprecated)

These are applied to frame and iframe tags.  I don't have any, so I've left these both out.  You should use Child Source instead of Frame Source though, as the later is deprecated.

Worked Source (worker-src)

This is applied to things like service workers, which I don't have, so I've left this out.

Frame Ancesters (frame-ancesters)

This is applied to frame and iframe tags, stating which parents may embed a page.  It replaces the "X-Frame-Options" header, but again, I've left it out.

Form Action (form-action)

This is applied to form tags, stating which location they can post to.  I don't have a form, so I've left it out.  In case you've forgotten, this means it defaults to the "Default Source", which is "none".

Upgrade Insecure Requests (upgrade-insecure-requests) and Block All Mixed Content (block-all-mixed-content)

My site currently runs on HTTP (non-secure), so I've left these out, but I'll definitely be looking to add them in moving forwards.

Reflected Cross-Site Scripting (reflected-xss)

Reflected cross-site scripting is bad!  I've set this to "block".  You can set this to "filter", which means the browser will try to cleanse the script, but I think it's safer to block it completely, if XSS is detected.

Manifest Source (manifest-src)

This is applied to manifest files, so I've set this to "self", as I have a manifest for icons.

Plugin Types (plugin-type)

This tells the browser which plugins they can invoke, such as the Adobe PDF Viewer.  As I don't think my site needs any, I've left this out.

Referrer (referrer)

This directive tells the browser when (and when not) to send the referer [sic] header when fetching content from another domain.  In my last blog post I decided to set the "Referrer-Policy" header to be "no-referrer-when-downgrade", and so I've set this directive to match that.

Report URI (report-uri)

This is where the browser will post violation reports to, so you can keep an eye on what content is breaking.  This could be because you've mis-configured your policy, or it could be because someone is trying to hack your site!  Scott Helme's excellent site report-uri.io will allow you to configure a URI which you can set here.


So now it's ready for testing!  

To test, instead of setting "Content-Security-Policy", set "Content-Security-Policy-Report-Only".  This means that the browser will report all of the violations, but will continue to load the content anyway, which is perfect until you're sure it's right.  

This is what I came up with...

default-src 'none'; script-src 'self' https://code.jquery.com https://maxcdn.bootstrapcdn.com https://cdnjs.cloudflare.com; style-src 'self' https://maxcdn.bootstrapcdn.com; img-src 'self' https://www.gravatar.com; font-src https://maxcdn.bootstrapcdn.com; upgrade-insecure-requests; block-all-mixed-content; reflected-xss block; manifest-src 'self'; referrer no-referrer-when-downgrade; report-uri https://rik.report-uri.io/r/default/csp/reportOnly;

I then reloaded my site, checked the console, and saw a number of violations!

This is because I'd forgotten a couple of included scripts that are loaded by Google Analytics.  In fact, they also use an inline script tag, but I really don't want to add "unsafe-inline" to the Script Source, otherwise all inline scripts could be run.  

Luckily you can fix inline script and style tags that you want to allow by calculating a SHA-256 hash of the contents and including this in the Script Source.  And Scott's got a hash generator tool as well, so that's easy.

Having fixed these problems, and reloading my site with no violations reported, I'm now ready to start enforcing.  This means that I need to set the "Content-Security-Policy" header, and if you're using report-uri.io then you need to update your Report URI directive as well.

Note that if you want to support IE11, you also need to set "X-Content-Security-Policy" to the same value.  It's not supported in older versions of IE at all.

Now that I've added these extra headers, you can check out my live report.  Last I checked, I got an A+ 😃

Saturday, 4 March 2017

Response headers - an update

I previously wrote about what response headers I was sending back from my website - now I have an update.

Part of the problem was that extra headers were being sent, which I didn't particularly want to be sent.  So I've been working on getting rid of them.

X-Hostname

I believe this is added by my web host, but I managed to remove it by modifying my .htaccess file with the following...

  Header unset X-Hostname

X-Powered-By

This is added by PHP, but it was easily removed by modifying my php.ini file with the following...

  expose_php = Off

Server

I could not change this, unfortunately, due to the fact that I'm currently using shared hosting, and therefore don't have access.  But for others, whilst it can't be removed, it can be changed to minimise it's output, by adding the apache directives...

  ServerTokens ProductOnly
  ServerSignature Off

So now I've tidied that up a bit, I wanted to look at what else I should be adding.  I found an excellent site for this by Scott Helme called securityheaders.io.  You simply scan your site, and follow the advice it gives you.  

It warned me about the "Server" header, but I've already worked out I'm going to have to live with that.  Other headers it suggested that I add included...

Referrer-Policy

This is used to define what referrer information gets sent when someone clicks on a link on your site that goes to another site, or even a page within your own site.  Scott Helme has written a great blog post on this, in which he recommends going with "no-referrer-when-downgrade", which sounds good enough for me.  My site is currently shipped over HTTP, but when I move it to HTTPS (yes, this is the plan!) then it will ensure referrer information isn't passed on to HTTP sites.

Content-Security-Policy

This is used to control what access different content on your site has.  For example, you can control what javascript and stylesheets can be included, inline or from different domains, etc.  Again, Scott Helme has written another great blog post on this.  He has also created an excellent site called report-uri.io which has a number of tools, including one to help you build your CSP.  This is a bit more involved though, so I think I'll cover this in a separate post.

Friday, 24 February 2017

Response headers

One thing that you need to decide when creating a site is what response headers to send when someone requests your page.  There are also a couple of different ways of sending them.  

Using .htaccess

  <IfModule mod_headers.c>
    Header set Connection keep-alive
  </IfModule>

Using PHP code

  header("Connection: keep-alive");

So what headers am I setting on my website and why?

1) X-Frame-Options: deny

This is the best way to guard against Clickjacking attacks, but telling the browser that it should never allow the site to be run within an iframe or frameset, and therefore cannot be embedding within another site.

2) X-Content-Type-Options: nosniff

This tells the browser not to try and guess the content type of a response and to always use the one being declared by the server. It reduces exposure to drive-by downloads and the risks of user uploaded content that, with clever naming, could be treated as a different content-type, like an executable.

3) X-Permitted-Cross-Domain-Policies: none

When clients request content hosted on a particular source domain and that content makes requests directed towards a domain other than its own, the remote domain needs to host a cross-domain policy file that grants access to the source domain in order to allow the client to continue the transaction.  I don't have any content like this, so I've set it to "none".

4) X-XSS-Protection: 1; mode=block

This tells the browser to protect against Cross-Site Scripting (XSS) attacks, and to block any attempts instead of trying to sanitise them.  This won't stop all XSS attacks, but it's a good baseline.

Now, if you check out the headers in the Network tab of your browser's Developer Tools, you'll see there are also some extras...



There are two types of extras...

Automatically created by the server - these are useful!
  • Cache-control
  • Content-Encoding
  • Content-Length
  • Content-Type
  • Date
  • Expires
  • Vary
Automatically added by my web host - these are not useful!
  • Server
  • X-Hostname
  • X-Powered-By
These reveal information to an attacker which they may be able to use to assist them, which is not good.  If I figure out how to remove them, I'll let you know in a future post.

Thursday, 23 February 2017

Making WCG Online secure

I'm going to talk about one of my projects - WCG Online.  This project has been online for a couple of years, and it's designed to give you, a valued member of the World Community Grid community, access to some more detailed statistics, as well as some lovely pretty graphs.  I'm hoping to add more functionality soon as well, but for now, that's the gig.

As the internet is slowly but surely turning secure (HTTPS instead of HTTP - check your address bar now!), and this site takes your username and verification code to get your stats - not the end of the world as it's certainly not your password and can only be used to view information, but still, best to be secure.

Having purchased (unfortunately my shared hosting package doesn't support Let's Encryptand installed my certificate, it was possible to access the site via HTTPS - excellent start!  But what about people who have already bookmarked the site as HTTP, or they happened to search for "wcg online" on Google and clicked the first result, in which case they would still get the HTTP page.

Having looked around a bit, I decided the best thing to do would be to change my .htaccess file and create a rewrite condition, like this...

  <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{HTTPS} !=on 
    RewriteRule ^.*$ https://www.wcg.onl%{REQUEST_URI} [R=301,L]   
  </IfModule>

So this is checking if the "HTTPS" variable is not "on" (as in, it's off, therefore HTTP) and then the rule changes the base URL to be HTTPS with the original request URI (the page and query string).  The "R=301" returns a 301 HTTP status to the browser, which caches a permanent redirect, so the browser should always use HTTPS moving forwards.

Unfortunately this didn't work for me (I later discovered my shared hosting package uses the variable "ENV:HTTPS" instead!), and nor did a number of other suggested rewrite rules, such as checking port 80, which is typically used for HTTP.  I ended up adding the following PHP code into the main page of my site...

  if($_SERVER["HTTPS"]!=="on") {
    header("Location: https://www.wcg.onl",true,301);
    exit;
  }

This essentially does the same thing, but it's done within the PHP code, instead of by the webserver layer.  Again, this uses a 301 HTTP status to tell the browser to always use HTTPS.

To back this up, I then added the following header...

  Strict-Transport-Security: max-age=16070400; includeSubDomains

This uses HTTP Strict Transport Security (HSTS), which if you're not aware, essentially tells the browser that it should always use HTTPS for this site.  This means that the browser will now use a 307 Internal Redirect, which is much much quicker as it happens internally instead of hitting the server.

The unfortunate side effect of this is that the site will forget you, when you first switch from HTTP to HTTPS.  This is because the local storage that it uses to store this information, as no information is stored on the server, cannot be access cross-protocol.  I think this is a small price to pay for security though!