 Hey, take it away Tim. Hello everybody. I promise I'm not that off my map. Anybody like to tell me which bike those headers are from? No? It's a random Honda one. It would have been really cool if someone had just yelled out about making a model, because I'd have gone yes in greed review. And it would have looked super cool, but never mind. OK. So how many people have heard about the Fairies now? British Airways hack, where they host lots of credit card details. Hands in the air. Anybody here actually affected? It's amazing. I've given this talk four times, and no one's been affected. It's almost like it doesn't exist. But quite a few people have, and it sucks. It really sucks. But when you do anything to do with security, what really sucks is when you realize that it would have taken them one line of code to prevent the whole thing. Now, you could argue that that's down to pure laziness. You could argue that massive corporations with good, big governance structures and things getting one line of code through is actually really hard. But still, we're in a scenario where just one line of code could have saved them and prevented at least their end users having any problems. Could user going to show you how to do that today? And this is not a scary talk. Yeah, yeah, that's 380,000 people. This is not a scary talk talk. This is just a very practical talk. If you want a scary talk, come talk to me in afterwards, and I can scare you to death. But I appreciate that some people don't want to be scared to death, and they just want to learn something. So, my name's Tim and Ash. I'm the WordPress platform leader for www.sp.com. I'm a form and pen tester. I cover on WordPress Leads. I used to run a small dev agency. I go around the country speaking about security. I have many accolades of disasters and doom and gloom to my name. I once almost destroyed the British Civil War, so please come and ask me about that. If anybody wants a hint, it's called caching, and it comes up in this talk. So, it also goes without saying, please don't do this stuff without further reading. Some of the headers I'm going to show you, and even just the idea of how headers work, can cause you to fundamentally and absolutely destroy your site forever. As in, you can get into a scenario where your domain name is almost unusable if you're not careful, because some of your users will end up in a scenario where they just can't be used. Also, security headers can be used for evil, which is not bad at all. But again, feel free to come and ask me about really evil uses of security headers. But yeah, please, please, please read stuff. Whenever something gives you the option of specifying a time, when you're testing, specify a really small amount. Then go to the 100 years. Really small. 60 seconds, 100 years. There are integers in between you can use as well. But do make sure that you don't just throw yourself into this because it will go horribly wrong. And I have screwed up a domain and I've had to throw it away, because I didn't. And I thought I knew what I was doing and, you know, arrogance gets the best of everyone. So, what is a security header? This is a normal HDB packet. This is the HTML and the HTML body in the HTML head. That's the content that gets delivered. This is normally called the response content. And up here is the response headers. These are set separately. So they're not part of the HTML. They're things that go alongside the HTML that tells you a bunch of information. There we go. So, this is just me making a curl request to my own site. And minus i, because curl works that way, gets me, returns me just the headers. And these are the headers that are sent with any content that's requested. So if you go to ask from my site index.phb, you'll get a set back headers that were something like that. Most of these we're going to be talking about. But things that are in your HTTP headers are stuff like status codes. It's things most people in the room will be familiar with. We've all come across the idea of a status code 200, meaning, OK, everything is good. 404's missing. 500, we're going into really bad territory. That's how the server responds and tells you that information is done for a HTTP header. Now, once you can do that for things like, hey, can I ask for what content type this is? 10 HTML. Can I ask what the server is, engine X? Why do I need to know what the server is? Can I ask for a bunch of other stuff for it? HTTP headers are very standardized, though you can put whatever you like in there. You will find, for example, if you go and look at some people's site headers, you will find things saying, what a job with us? Click this link. Or if they're Terry Pratchett fans, you might find a GNU Terry Pratchett header knocking around in there. Oh, clack headers. So there are lots of uses, not just security uses. Now, a header can be sent by both the web server, something like engine X, or the application, OK, WordPress. Now, if you're using PHP or WordPress to send headers, they have to be sent to the specific point. They have to be sent before you start generating the HTML body. Because if you don't, well, then you get that fun error message that comes up saying, I've already sent the headers, what are you doing? You muthits. So which one you choose will depend on what you want. Normally, sending the header via the web server is faster, because obviously it's not doing any work, but they're normally fixed at that point. It's unlikely that you want to be dynamically generating your headers via the web server. If you need to dynamically generate the header, you probably want to put it in the application, OK, WordPress. As a general rule of thumb, things like a HSTS header, I would probably put it in the web server. A CSP, which we'll talk about later, I'd probably put it in the application or let the application determine it, because I might be dynamically generating it depending on what page is on. That comes with its own sets of risks and issues, it's generally probably much more flexible. Now, if I can set a header in the application, that means anything that's got control of the application layer, or basically anything that can interact with a HSTP packet, can set headers. Do you remember that bit where I told you, headers are dangerous? This means that any WordPress plugin, for example, could set a header that just says, turn on HSTS. I don't care if you don't have SSL enabled. Forever. Preload it. Whisk it. Also, if Bob, who's not a system administrator, besides he wants to put a header on, he can put it on, and he could potentially put it on a sub-domain and affect the main domain. It's all good fun. This is why some setups will actually prevent application level from setting headers. So, let's start with some headers. First one. HSTP strict transport security, or HSTS headers. This is probably one of the older ones that most people here hopefully might have come across it. The idea is most people's site goes over HSTP, goes over HSTS, so SSLO. Now, if we want to say, actually, under no circumstances do we ever want the person to go over HSTP, we can say, set a header, leave a max age, in this case, 300 seconds, and say, whenever you, as the browser, when the browser makes a connection, we say, hey, we want this browser connection to always go over HSTPS. Next time the person comes to the site, even if they put in the URL, http, timnash.com.uk, the browser will go, no! The site told me I must load over HSTPS, and that is what I will do. And there is no way for the site to override that again. Up until the max age. I will not ask for it, I will not request it again, I will just assume I must go over HSTPS until I get past this max age and I will request the information again. Awesome, we now know that our connections will be always over HSTPS to our site. This is a good thing, generally. We've now increased our max age, you'll notice here, we've got a bit longer, we're raving. We can also say, include subdomains. So now, anything over timnash.com.uk, meta.timnash.com.uk, dev.timnash.com.uk, local.timnash.com.uk, all must be going over HSTPS. So even domains I've never thought of, the moment I create them, they must be going over HSTPS. All my browser will say I'm not connected. Now, here's a real phone one, some browsers, if you're on the subdomain and you include this, will include that for the parent. So you can own blahblah.wordpress.com and if you manage to get a HSTPS header on, you can force it for the entire of wordpress.com even though you are actually only controlling the subdomain. Yay, fun. On the whole, HSTPS is a good thing, but you need to think about implementation. If you have local dev environments that you wouldn't naturally have over SSL, you now have to have them over SSL if you want to include subdomains. Suddenly, you might be all thinking, I know, I'll change my local dev environment to be, I don't know, timnash.dev. I wouldn't do that particular one given that Google owned the .dev domains and they've specified that HSTPS is preloaded. So you're back in the same problem anyway. HSTPS. It is useful. It will prevent man in the middle attack. So the idea is that I go, hello. I would like to talk to Tim after the game. Somebody in the middle goes, oh yes, that's me. Just giving you the information. By the way, I'm just going to give you the wrong information and pass it through. So it does have a use and it is important to use it. Just be aware that this is one of those potential ones that can totally screw you. So make sure you're fully aware, before you include all your subdomains, all your subdomains actually are over HSTPS. We can also say preload. The idea here is that once we say preload, browsers will start to go around and find these preloads and put them in preload lists. You can also submit it to something like HSTPSpreload.org. Now you have to have a certain length of expiry time. There's over a year. But you can then say, and it must include subdomains. I'll double check that. Pretty sure it has to include subdomains. You can then ask the browsers to preload this. Now this means that the browsers never have to make the initial connection to get the header. So for example, Chrome, if you come to my site in Chrome, it never asks, it never goes to check the HSTPS header because it's already preloaded in, so it knows that it should only be loaded over HSTPS. This certainly becomes a really useful feature. Until we don't load over HSTPS. We have a bad day. We let's encrypt certificate and renew. Now your site can't be loaded at all. The browser will refuse. Or worse, we'll try and load it anyway and it will just get stuck in the loop. That said, everything should ideally be preloaded. Moving on. Cross-site scripting protection. It's a very simple header. In this case, it says zero. Most browsers have some built-in cross-site scripting protection. Basically, they look at the URL and go, do you know script? A script and then a bunch of JavaScripts in the URL encoded is pretty weird. Maybe it shouldn't be there. We'll try and strip that out. So you can turn it on. And in this state, you can just turn it on and it will just sit there going up. Well, I know that that's not right. I'll put a message in console. We can also use this report. Report. So the report allows us to go to this URL and the browser will send to that URL a JSON payload. It makes a post request to the URL that you've specified saying, hey, tell me about any issues that you've come across with cross-site scripting. So I can say, hey, what did you get? And it says, oh, look, here. This was the request URL and I didn't have a body. Here's the information about it. This is bad. So the browsers are now telling us when things are bad and broken. This is really cool. Because we can now go, something's wrong here. We can go and fix this. Now, a couple of ideas if you are using things like this. One, you probably don't want it reporting to the same domain that's got the problem. Because there's a reasonable chance that there is a problem that they've probably got your reporting URI as well. Two, if you have a problem, every request at every browser can start reporting stuff to you. You can end up quite easily dedotting yourself. And it's very hard to stop because you've told the browser to do it. Oh, and headers get cached. So even if you took the header off, for a little while, the browser's still going to do it if you've been to the site previously. A good service is Report URI. It basically is designed to provide a reporting services for excuse's sake. They're based in the UK. They've got their servers are based both in the EU and the States. You can specify specifically through. It's got some really cool features. So if you are looking at setting up reporting, I would recommend looking at Report URI. So up until now, we've just reported stuff. If we mode equals block, we'll now say we do not want you to load that resource. I've decided that I'm pretty sure I don't have any cross-site scripting issues, things that would look like scripting attacks. So I'm willing to put mode block. Now, sensible people, we start with this. We get it reporting. When we're happy that there's no reports coming in, we go to this. Do not jump to this because your page might not be loaded. Because just because you think something doesn't mean the browser does, trust me, their rule set is pretty basic. I mean, pretty, pretty basic. Not there anymore, but in the earlier version, one of the browsers, except if you had the word union anywhere in your URL, blocked it as a cross-site scripting attack. This sucks if you run union jack stock. We can also set it up so that we both have reporting and mode block, which would be our ultimate goal. Moving on. Next type. This again, the real header. So in this case, it's just x, so x normally means it's outside of the standard specification. Even though these are standards that most browsers adopt, they're not formalized standards hence the x in the front, hence content type, options, no sniff. Now this basically says, if I load a body inside the body, it's just got style, and there's style sheet, and it's just got JavaScript, then do not try and guess what it is because it's told you. So, if the mind type is not text hat, text slash CSS, then that's stuff inside there we don't trust. Likewise, if the mind type isn't JavaScript, or one of the, there's about three different JavaScript ones, do not trust it and do not load it. Refer a policy. This is for giving information and going forwards and backwards. So the most hard version is no referrer, so don't pass to the next URL any information about the URL you've just been on. No referrer with downgrading, that's going from HTTPS to HTTPS, or HTTPS to HTTPS. Only do referrer to my own domain because with no referrer, even pages on your same site will not share referrer information. Origin, your stuff. Origin, going down, going down, same one. Now on to the ruby bits. Up until now, these have just been one-off headers. Content security policy is a single header with lots of information in it. And in many ways, CSP has subsumed a lot of the stuff we just talked about. Cross-site scripting protection can be done purely with a CSP. They work hand in hand because the CSP will block based on what you tell it, whereas the cross-site scripting protection blocks on what the browser was thinking about. So a CSP policy, we'll start with something simple. Was it a default source? So self, my site. We can say that, unless I tell you otherwise, the default source for everything should be self. Self and everything in friend.up. Because, you know, everything should have come from self or friend.com. So default, if you, rather than using self, if I don't want to specify, if I want you to only be loading over HTTPS, I don't want to put subdomain, I want to make sure it's protocol-specific, I can put my actual domain in there. We can then say, okay, for images, I want to load from anywhere. And there are scripts, so for JavaScript, I want to load from self and friend.com. So my default source for most things is myself, but I'm being overwrite, so each time we add these steps, we're overwriting the default. For images, I'm not, you can load them from anywhere on the web, I don't care. The scripts must come from self or friend.com. Oh, we can report stuff. This is good, because now we're going to get information back and dedot ourselves when we get this all horribly wrong. So a report coming back will look something like this. Again, it's a JSON payload has, now, the amount of information that's given to you will totally depend on the browser, because what Firefox gives you is different to what Chrome gives you when, yeah, well, other browsers do exist. No, that should be it. But yeah, so what's in there will change, depending on things. And if you've got your however you've set as you refer a policy, obviously it will affect this as well. Very true. So we can also set our content security policy to be report only. When setting up your CSP set it to report only. Because if something violates your CSP the browser will block it immediately. Your question's asked, that's what it does. It will tell you in the console and it will report it to the report URI, but it will block it. Let's go back through. Scripts, we could do self and by default just because something's in self. Unless we specify unsafe inline any script that is inline or any style that's inline will be said no because it's not being loaded as a remote resource from self. So we could specify in our script source unsafe inline. That would be bad because we don't want unsafe. The fact it's got the word unsafe there probably gives you a hint. But this basically means we're going to load script and say anything that's on the page arbitrarily just let it go. Obviously if somebody can get an inline script on the page maybe they've managed to get an injection into your posts, into a post that will just process. We don't want that. So all we can use is a knot. So we can have our random nonce and then we can say for this nonce here anything that's got that nonce as well will let that run. But we won't let it run unless that's there. So we can specify these nonces. That's brilliant. That makes life so much simpler. So then we can say we can specify even the remote script. So my trusted script, it's got a nonce. So we can specify whether it's inline or it's got a nonce. If it hasn't got a nonce we're not going to load it. You see, nonces only work if they're randomly generated on each page load and that they're actually random and that we can be used once. Hence the name. If we cached the page we've cached the nonces. Now, we could break out of the caching but then we're broken out of our caching. Suddenly if you want to have a high-performance site and you want to use nonces you either have to lose the security or you have to lose the performance or apparently you have to lose high-performance all. So, let's go for an alternative. Instead of using a nonce let's hash the results. So if we go back here we've got our script. We go to our script and we actually make a hash. So an sajt56 hash of that whole content that's everything from this point here to this point here. We hash that and all the content inside of it and then we can specify that in our content security policy. So now, there is obviously a miniscule chance two identical blocks of code could have the same hash. But if that happens to you run to the nearest place by a single lottery ticket and then buy your airline ticket because you've won. That's, yeah. But on the whole, this is a pretty safe way of putting in hash. Now we just need to hash each time. Great, because code never changes. We never push out new builds and stuff. So this should work 100% of the time very efficiently. Actually for static sites or sites that are very rarely changing this is quite a good system. If you've got anything that's going to be dynamic and changing regularly you're going to have to start thinking about build scripts and how you want to modify your build scripts and then you're going to have to use SHA256 hashes. Are you going to? Seriously, if you've had to play with caching and you think that's crazy you've never tried checksum or something. Because it's amazing. You'd think that the whole point of a checksum is they should be identical. There is no way that that checksum could possibly change. Yep, they do on all sorts of things. Whether you used a Windows machine to do the checksum or whether you used can make a difference to what the result of the checksum is depending on line endings. All sorts of fun and games you can have. Checksumming is never as easy as it comes across. Which leads us on to something else. SRI, self-resourcing integrity. This is basically hashing again but instead of putting the hash in the header we can actually specify integrity here as this. So now we can say hey this script which is a remote script, I know about this script and I know the hash for this script and you should only load if this script has. You don't need to use a script header for this you can use it on each script. So we can say I know about all my scripts and I know what the hash is going to be. We can also then specify in our CSB you must have an SRI for script and style. So every script that is loaded every style that is loaded every inline script that is done every inline style that is done must have an SRI. Brilliant. This is a really good world because now you cannot change anything on my side without there being an SRI and you have to generate an SRI if you are going to hack me. Hackers don't tend to go around and say I must add some integrity checking just to be on the safe side into the system. It happens though we then use the same hashes in our CSP to say I will only load these hashes. Brilliant. It's wonderful isn't it? It's not. It should be. It should be a lovely future up until you realise that you load Google Analytics. Because Google Analytics you can do an integrity check of what that particular file is now but it will be controlled by somebody else it will change. It's dynamic in its nature it changes on every page then just to be more fun you remember when we said require SRI for scripts that includes scripts that scripts load which means we basically have to know all the SRIs and have SRIs set up for every single script that Google Analytics loads or YouTube loads they load a lot of extra scripts from lots of extra domains. Just writing a CSP policy can manage to get YouTube to load is masses of extra domains in there. SRI is brilliant. If you have a small static site using SRI it works really well. If you have a site that is on the front end is very light it works really well. SRIs for WordPress admin areas that you don't try not to use the words unsafe inline is nigh on impossible because every single plugin loads in and some of them will enqueue things beautifully. We can grab anything that we enqueue and we can hash that. They do an inline. We might be able to find the action who can find it. We can buffer the output and hash all of that and just buffer the bad stuff as well. We don't have any standardized way for just adding styles on the admin area that is used. We have hooks and options but at the end of the day someone will go yeah but I'm just going to shove my scripts in the footer. We have no way of grabbing that information and knowing which ones are legit and which ones aren't. If anybody has successfully managed to create a CSP that is actually not in the admin area I'd love to talk to you because I've been trying for about two years to come up with various ways to do this and barring being incredibly selective with my plugins choice which is how I succeed. So I can do it from my own personal site. That's fairly easy but then I only have half a dozen plugins and I've wrote most of them and I know what's being enqueued and I've gone for each page carefully decided this isn't a good space and I've gone and put various hashtags in. If you've got clients and they have a tendency to go I know I'm just going to install my e-commerce software over there and that one and that one and I want it read and changing everything then you are screwed your admin area will never be in that nice state but you can work on this stuff on the front and so as much as CSPs are really designed for both the ends of the site using a CSP and using all of these headers they're here to protect your users. In many ways they are here to provide protection for your users not for you because if you need to trigger a bunch of this stuff you've probably been hacked that's probably bad for you because now we're trying to just prevent malware being spread we're trying to prevent people using your site for DDoS and other things so this is all about protecting your users and as such the front end is a good place to go. How would the BA hack been solved? Well if they had a content security policy that just specified which domains they were going to use and just set it to themselves and a couple of trusted partners that would have blocked it. If they used SRI that would have worked their way if they just used any form of hacking on their resources it would have worked. It's interesting, BA now have a CSP policy in place it wouldn't prevent the hack but they have one now improvements there's just one more header headers are being added all the time but this is a really cool header that I generally implement almost like that but I will do. That's a feature policy you can actually say hey browser I like you to specify that I actually don't need to use the accelerometer today I don't need to make payments I don't need to use the gyroscope I'm not going to ask for your geolocation and any of that in fact I don't want to use the USB I just want to just be left alone and you can specify which features should be on and off this is actually is really useful because things like push notifications and payments and all these interesting little things that you can trigger to get the site to start using we can turn off and make sure that they're just not going to be able to be used in any way it also stops your developers from if you're a sys admin and you really don't want them to put up little things that says please share our location because you just hate them and you think that the UX designer doesn't understand it yet you just turn it off and prevent them from harassing it and then claim you don't understand how it's not working if you want to go check out how your site is doing currently you can go to security headers.com and you can put it in your scan click there, put it in your scan it will bring back all the information to link to how to implement them in various ways report URI which I've already talked about and observatory.mazzilla.org which is basically the same thing again but through Mazzilla I told you this wasn't scary thank you very much yeah I know this is really mildly traumatised come on someone's got a question for Tim right Louise so you certainly lost me on how you do solve that problem if you can't cache things oh sorry so what can you do okay so you can't it for caching we go back so using noxes yeah which we generate each time if we cache it then we're screwed so to get around that we hash the actual content itself so we've got the hash which we know doesn't change and we just we put the hash for each one in there so we wouldn't have just one hash if we had 10 scripts running we'd have 10 hashes inside our posts so your build script would have to generate those hashes yeah on deployment because otherwise the code would have changed yes do you want to have an example which has a hash in there no of course I don't that would be way too easy so it's clear I had the conversation but it is for style not but that also gives you an idea of just how many various twitters and youtube videos you'll find lots of them to load youtube you need it to be in your image your source your frame source your media source and actually to get it working with some of the older browsers you also need it in bed source not just youtube you also need ui whatever it is I can't remember the sub ones for that is it's a pain use video press apparently they only need it in one location but yeah so you'd use it that's alright but you'd have to generate that in your build script anybody else the self policies is that limited to just the website or any plugins that use external resources if the user external resources is being loaded by the browser then it considers not self if the website was making a cool request and then returning it itself that would put itself so one of the options for getting around some of the stuff with google analytics for example in fact quite a lot of people who like to get 100% on google page speed they like proxying google analytics that additional analytics source if it was proxy would be self but if you were just including google analytics js from google then that wouldn't be yourself and that would be good for it can we have these slides available online? they are at a URL that's on the screen any other questions? let's do that one and then doing that who's no doubt going to do a comment rather than a question our reputation is on that you mentioned that new headers are added all the time who is it that? browsers so a combination the input community as a whole there are mechanisms to allow them to communicate with browser companies but yeah it's the browsers we implement just like anything to do with browsers some browsers implement stuff quicker than others and some don't implement stuff at all so there is a little bit of can I use this style set up and in fact if you've ever used can I use for anything to do with JavaScript and CSS and stuff most of the security headers are on there as well they're actually planning on separating and making a separate section on that so hopefully most browsers every major browser supports the only one that's not supported by every major browser that I've shown you today is feature part policy which I think is only available in Chrome and Firefox but it might be in Safari as well surprisingly Safari are pretty good at implementing security headers which is weird they're obviously implementing anything else and this is their own stuff actually Tom do you have a question or have you got a long statement so I've been trying a while ago I found security headers.com and I tried setting up my own content security policy there were a few headers I wasn't aware of there but there was, you talk about unsafe inline I tried to eliminate unsafe eval I think it is and ended up breaking half the review I think the media manager wouldn't work do you know anything work around that's trying to change the code so it does work? So I managed to get after about a year and a half of swearing I did manage to get most of the media stuff working anything that is acute properly acute using work at hooks is fairly easy to do because we now know what we're getting and so we can create a hash for that and we can normally modify it where it falls down the moment of plugging gets involved you're A fighting for control over who's modifying that action first but also you end up in a scenario where you don't know what that comes in should be or shouldn't be so you have to treat it as untrusted and that's where it all falls down so it is possible to do it for most looks and features a couple of places that couldn't get it to work properly good and bad you just can't get it to work but that's not good but yeah, good and bad you can't get it to work just because of the nature of how good and bad it works I probably could if I spent the next two years trying to do it I have a day of working with the classical editor and it got over a thing set up with media working oddly enough the dashboard itself it has a bunch of scripts that are added but aren't enqueued properly and they just generate in the foot just for reasons and the settings page again has some save bits that aren't enqueued properly and once anything that's not being enqueued probably is basically where you're going to fall down there isn't any particular will amongst people as far as I'm aware to try and make this better over that's a shame but because it is quick wins but the problem with that is a quick win for WordPress core but as we can't actually set this to enforce because we know we'd have to get every single plugin to do this as well it becomes an academic issue really because until we can work out a way of making enforcing that for plugins and even if we could get it to enforce for plugins we might be then whitelisting scripts that we definitely don't want to whitelist anyway because it's the plugin that's been hacked and if we automate the ability to whitelist things it won't take too long before somebody a bad actor goes oh I just think you must go properly then job done so this isn't the roadiest of talks but it's a better talk than normal well that was an excellent talk thank you so much folks do have questions I am around for the rest of the weekend please do come and approach me and if you just want to come and chat about security stuff please do come and talk to me I always like to give out security