
[Music]
hello hi everyone I'm Devin Lundberg I'm here going to be presenting no more cross-site scripting about deploying content security policy I'm currently the product security lead over at Pinterest and I've deployed content security policy on Pinterest comm Instapaper and a bunch of internal tools there and I hope that all of you can take something from my experience deploying it so first off I'll go over some background with what cross-site scripting is hopefully a lot of you know what that is and what content security policy is after that I'll go over to newer directives that weren't around when content security policy was first created the first one is nonces the second one is strict dynamic and lastly
I'm gonna go through the step-by-step instructions with some code samples on how to deploy content security policy on your site for a site where you don't have any sort of content security policy so let's start off with talking about cross-site scripting I'm sure a lot of you have seen this cross-site scripting has been around since I think it was first found in like the 90s basically it is a bypass the same origin policy on the web which allows one domain to talk to another domain specifically in the case of cross-site scripting it allows a malicious party to run a script in the context of an origin they don't control so an example of a classic cross-site
scripting vulnerability is you have an air page and you can catenate your error message with some HTML and you don't do any escaping as you can see in the vulnerable server code here and someone puts in script alert and the browser gets the script alert tag and then it's execute set script obviously an alert isn't very dangerous but you can get really dangerous situations because you can do anything that the webpage could do one example of a cross-site scripting being used in the wild a lot of people saw was the Sammy worm on myspace so if you remember myspace it was a social networking site that's not very popular anymore and a guy named Sammy found a
bug in there their profiles that allowed him to add a script and so he added a script that basically added him as a friend and added the script to add him as a friend and add that script to anyone who viewed his profile and so he gained a couple friends over the first hour and then by the end of the day I think he had most of myspace as his friend just by people viewing his profile and adding their script to the page so it can cause some pretty serious problems and it basically has full access to everything that the web page has access to good news is that there is a pretty good solution for cross-site
scripting in the generic case which is templates and auto escaping so in most major browser frame or web frameworks they're out there if you create a template so something like Django or Rails it might look something like the top where you you have your error message in there and if you pass in an error message with things that look like HTML what it'll do is it will escape them it will assume that there are text input and they are not formatted as HTML and what this does is allows you to prevent cross site scripting by default so great problems solved we don't need worry about anymore no cross-site scripting is still one of the most vulnerable or one of the most
common web vulnerabilities out there there's a lot of cases where developers want to turn Auto escaping off for instance if they're building out features likely fication where they need to take user content and turn it into markup so in this example I'm sending a message to to my friend on Pinterest and it has a link in it and we want to make it clickable because that's a nice user experience but we need to make sure that the logic that makes that clickable can actually handle all the complex cases around escaping and it's actually very easy to get wrong other cases like internationalization are pretty common and then there's just cases where developers don't know any better
things like Django and Rails the the function for marking things as as HTML is called safe so developers think that they're making something safe by calling it newer frameworks like react will actually use longer dangerously set in or HTML so it's a little more obvious they're introducing a security vulnerability but you can still get problems with those so introducing content security policy content security policy is a HTTP header and what it does is it defines a list of who can access resources on your page and you can actually do this for different different types of resources on the page you can do things like these are the list of domains it can host JavaScript these are
the list of domains that can host style sheets these are the ones that can be on I frame x' xhr requests all sorts of things images media forms you name it there's probably some sort of directed that covers it and it's really useful in the script source sense and so we're gonna focus in on that for most of this talk so this is actually the current content security policy for Pinterest it's nice and big on this IMAX screen so you can actually read it I wasn't actually sure if you would be able to but this is an example of sort of what a domain whitelist looks like so you can see that we're white listing some
wildcard or origins and a bunch of other origins in our script source so we can run those pieces of JavaScript on our site we also include things like unsafe eval which allows for eval statements to work which can also be dangerous by default content security protects you against those and unsafe inline allows for inline JavaScript to work and this can cause some security problems that I'm going to talk about in a little bit anything that's not covered in this whitelist is block if you're just using the content security policy header as you see here there's also a content security policy a report only header that will just report on any JavaScript that's not on the
whitelist some other directives they're really important if you're worried about cross-site scripting and preventing it with content security policy our object source and base URI object source is the source for including things like Flash and Java and plugins into your site if you have a modern website you probably aren't using these things it can safely set it to none if you're using something older or something where you you really like Flash for example you can just make a whitelist just like the script source base URI is for preventing the base HTML tag from being set to other origins this is basically used for studying what relative URLs point to so if I have a link on the page that points to slash
what homepage will it actually point to by default is to page you're on but if I set that base tag to something else it'll point to another domain this is also used in CSP to denote what self is so if you don't set this to none an attacker could basically include an origin they control in your list so really important that you set it to none or if you're actually using the base tag I don't know of anyone who does but if you do that's fine you can also include a whitelist so let's say your content security policy actually has a very good whitelist set up and it's blocking scripts from being including your page
what can an attacker still do and I'm gonna call this HTML injection because you're not doing scripting anymore because your scripts are being blocked so with HTML injection there's some really interesting attacks I highly recommend you read github as a really good blog post on it and so does a former Googler letters from a post XSS world so these are really good articles on this but the the main attacks are defacement which is you actually include content in the page like you say hacked by blah blah blah and it will render in the page so it's sort of like a text injection sort of thing redirects you can use markup to redirect the page to
another page and then do some sort of phishing or something along those lines form parameter injection so if there's forms on the page you might be able to take over the forms and inject hidden parameters the browser will by default only use the first parameter so if you have the the HTML injection before your form you can actually override what the user inputs and then data exfiltration that's probably the most serious out of all these where you you include dangling markup or or things like image tags where you can actually exfiltrate data from the page github x' blog post actually goes into depth on how images were used to extract Caesar tokens from their pages so those are some things you
still have to watch out for but overall it's a much less serious attack than than what you would get from a cross-site scripting attack normally because the attacker can't do arbitrary things on your site they can't make requests on behalf of the user and read the responses they can't they can do a lot less and in our experience we've gotten many reports of cross-site scripting attacks over the years and everything that we've gotten since deploying the content security policy is less risky than what we had before we deployed the content security policy so it can turn incidents into bugs and this is a really valuable thing for us because it saves us time from an
organizational standpoint and it allows for easier prioritization against other company objectives ok so I mentioned that there were some problems with inline scripts before so I'm going to talk about nonces and how they're a solution so let's talk about inline scripts these are super common in web applications this is where you just include script and then you start calling JavaScript functions they're really easy to use so web developers tend to use them a lot there considered not great practice from a front-end engineer standpoint but they're still all over the place so when you're migrating a legacy app actually going through and finding all these locations and moving them to a static file or a single javascript file is
actually not trivial there's also the problem of performance inline scripts actually have much better performance if they're short on a web application so you might actually hurt the performance of your your site by moving these to a JavaScript and this actually blocked us for quite a while we had a an early version of CSP on our site and we could not migrate completely to get rid of unsafe in line because of the performance impact it was it was a big impact and it would hurt our users so what can we do introduce CSP nonces nonces are a number used once that's what nan stands for and basically every time a page is rendered you generate this random number that looks
like this is ill Babinec thing it's generated on every page load and it's made to be random and not guessable so I typically go for 128 bits piped into a base64 when you include in the header you need to also include it on all of your inline scripts so it just looks like this in the header where he has nan stashed the random value and then in your in the body on every attribute of the script it includes nonce equals that value as well and because it's unguessable the attacker can't inject an inline script so you you actually are safe against inline script attacks and for backwards compatibility it allows you to also insert unsafe inline so
you'll still get the protections of CSP if your browser only supports CSP v1 rather than CSP v2 so you can include unsafe inline and still get those protections what can go wrong if the nonces are exposed in any way the attacker can use this to to run scripts on your site and you lose the protections so you really need to be careful about non-serious you can't use these in more than one page you can't use them on cached pages data exfiltration is also a problem so you generally only want to include them on your script tags themselves you don't want to put them all over your page so they can be exfiltrated through other means or include them in vendor scripts
or other parameters browser supports pretty good on nonces I think it's if you use can I use I think it's like 80% right now modern browsers like edge Safari Chrome Firefox Opera all support announces so the support there is pretty good right now I mentioned you can't use them on cash static pages and that's where hashes come in cash static pages tend to not have user data in them so you tend to not be as vulnerable to XSS on those pages but there is a solution for you so you can protect these if you do have some sort of data that's echoed back so how hashes work is you basically take a hash of the actual contents of the
inline script and you base64 encode it and you include it in the the header - what type of hash you use so I think shot 256 512 and one of the other ones of the shot - variety and it also has that great backwards compatibility feature where you can include unsafe inline and it'll just ignore that if the browser supports hashes whitespace and capitalization do matter if you're deploying hashes so don't forget those in your script tags if I included an extra space my my hash will change on my script value so this is the hash of var space in line space equals space one semicolon and you have to be careful of that when you're deploying that great so
strict dynamic there's one other problem that is a really big deal when you're deploying content security policy which is that you have to maintain that whitelist domains and getting that whitelist in the in the first place is actually kind of difficult you have scripts on your page that might include other scripts on your page that might include other scripts on your page and so figuring out what those those dependencies are is something that you actually have to go through and monitor and figure out so from an operational standpoint it's difficult to do that and then also from a maintenance standpoint if facebook decides to change the URLs of what they include with their script then you know their plugins might break
for some amount of time until you figure that out so from an operational standpoint that's not so great from a security standpoint it's even worse because you tend the whitelist things like CD ends or outside vendors that you might not know exactly what's what's happening and what kind of sources they're including on their page so they might have a user upload function that allows them to upload other users content one example of this would be storage that Google api's comm which we had white listed it at one point and that basically is any any Google cloud user can upload to that domain so you have to be really careful about who you're whitelisting the other
side of this is there's a somewhat bypass using JSON P so if you're not aware of JSON P that's where you can include a callback in your your script and allows you to get around the same origin policy unfortunately with these white lists if you include that callback they could name other functions inside your page and they could use that to execute sort of a strange attack where they're tying together different function calls it's kind of difficult I've never seen it actually perform but it's they can still execute an alert for instance so the solution for that is strict dynamic and if you include strict dynamic in your script source what that means is that it will trust anything
that's white listed with a nonce or a hash so in our case instead of just adding the nonce to our inline scripts we're also going to add it to our our full-on dependencies so in this case it'll ignore the white list so we could we could even include a different domain here if we wanted to and it would be fine in a browser that supports ESP ESP 3 and what this does is it basically says anything with a nonce is okay to run and anything that these pages include is also okay to run so that pin image comm slash site dot J s might include another domain that includes scripts and that's okay as long as the
JavaScript that's already trusted is is including that script so things can go wrong with that so you might have JavaScript templates that render render your content and there's actually a good number of bypasses there so if you're using angular v1 there's I think what the other ones are I don't remember the other ones up top my head but angular v1 is a great example of a case where if there's a script injected inside of an angular template that will bypass strict dynamic if you're using something like react there's no bypasses there I would recommend whatever framework you're using if you're rendering JavaScript templates you double check with the research that Google did about a year
ago in across CSP but if you're using react it's great it also isn't supported in I 11 edge or Safari so you don't get as good of browser support as you do with nonces and it means you'll fall back to the white list for deployments for those browsers so if you whitelist something broad like HTTP which is all web pages and you won't get any XSS protection on those browsers so now that we've gone over the the new directives and sort of what they offer I'm going to talk about deploying CSP using these directives this actually tends to be a lot easier than it was to deploy the first version of CSP because the first
version of CSP you had to construct that white list and that's actually a pretty tedious step the other part is removing inline javascript which also tends to be really tedious so this tends to be much easier and you can get that protection much quicker for example with instapaper I was able to deploy this in about a week the first step is the hardest step this actually involves code changes things that can go wrong one thing that CSP doesn't allow and doesn't protect against is removing JavaScript events so if you have like a button that has an on-click javascript event on it that does something you actually have to change that to be an inline script tag so any of your
template files that look like the the top part where it says on click do something you have to change to document that get element by ID or by class and then add an event listener onto it and this is the step that's in my experience most prone to causing errors you should test very carefully make sure you don't change anything you typically have to do this manually because you'reyou're adding IDs you're adding classes to your your existing templates and you might mess something up there so after you get those code changes out of the way you get you have the hard part done the the next step is to add a nonce generation middleware to your web application
there's some great open source projects out there whatever language you're using or framework you're using I recommend you just search github for something and if it looks like it's you know solid versus your open source guidelines whatever those are you should probably use that rather than building your own but it is simple if you want to build your own so if you do want to build your own I would recommend 128-bit nonces or 16 bytes you generate a random string from a good source of randomness use Debu random or or whatever your cryptographic random number generator is and then you base 64 encode them and you keep track of that nonce is in a place
where your templates will actually be able to access them so in Django putting on the request object generally works pretty well so after you have that nonce object accessible you need to actually change your your templates to use the nonce this tends to be a pretty simple step especially if all of your templates are in one place because you can just do a find and replace for less than script and replace it with less than script space nonce equals whatever your format of their template is in fact if you use something like closure which Google modified to automatically add nonces to all their script tags if you enable the flag so maybe your template engine
supports that and if they do even less work for you after you do that you can test CSP in report only mode report only mode basically says you specify a URL and it will send reports on things that are getting blocked it tends to be kind of noisy if you're deploying it to your users but if you get high-volume reports those tend to be things that are actually going wrong there's actually a pretty good resource on going through and seeing what kind of things are getting block of your CSP examples of things that are pretty common are like browser extensions especially in Safari I think like every browser extension or a good number of them will will generate
reports but you can generally see large amount of failures for things that are actually breaking your site the other option instead of going to report only is to gradually roll out the full header so if you have some sort of experiments framework or something like that where you can do that that's also a great option last step is you remove the report only from your CSP header and you continue monitoring your reports so this is actually an example of a CSP policy that will work for pretty much any site out there what it'll do is it you replace that random with your random value and it will block anything that you don't have white listed in finance
and it will block all flash so with this you won't be vulnerable to cross-site scripting just HTM Injection on browsers to support strict dynamic you could even take a six step here to add your own whitelist and then you'll get protection in Safari and edge as well so again these are the five steps as I mentioned they tend not to take very long I've done them on a bunch of internal tools and I've also done them on insta paper if you're going from a site with an existing content security policy which is what I did for Pinterest they tend to be even simpler because step one is generally already done for you so it's just the adding the nonce
generation and then rolling out the header I'll try to post these slides somewhere there's a bunch of links that are super useful google has great resources on deploying CSP so I recommend leveraging them CSP that with Google com will actually go through the steps that they recommend going through they have a github page with those security research pocs which are bypasses district dynamic in common security libraries so if you're using ember j/s or some random other one that's not angular or react you can look them up on their CSP mitigator this won't let you test nonce is very well but if you're constructing a whitelist it's really useful because it lets you put a CSP in your your browser and
extension and go through and test fittings and then the link to those two blog posts github.com slash nico 3 333 FR whoever that is has an awesome list of CSP links in related content they also have a section in there that c CSP WTF which basically lists things that you you might not expect it'll show up in your reports so you can go through there and you can see some some examples of things and then lastly there's the spec for CSP it looks like we have about four minutes left so some time for questions thank you all for staying listening I hope you do deploy CSP on your sites make the web more secure [Applause]
yeah so for instance changed and it is actually a good amount of work to go through it tends to be very repetitive I don't have a tool for it because it's kind of hard to automate in a templating system where you might you might be generating things in a for loop so you can't just apply an ID to to your script tags or to your to your elements to be able to find them in the page if someone does have a tool or builds a tool that's awesome but it's probably gonna be template engine specific I guess is so yeah it is kind of tough but it tends to be less common than the actual script
tags themselves or at least it I found in my web app stepped on through but it is a good amount of work yeah so we actually so it's not masked this is actually our report URL it's slash underscore slash underscore CSP report so what happens there is it sends a JSON object whip from the the browser that basically has a full report with all the details and what we do is we we log it to s3 and then we have we have an e okay start up in front of it and we we search it through that yes so it's a post request too so this is a relative URL but you could do it on another domain if you wanted so
it doesn't post requests to do Pinterest comm slash underscore slash underscore CSP report yep and then you can you can record that in whatever way that you think is suitable for you
let's give it hands para speaker [Applause]