This is part #2 of a series on the OWASP Top 10 Proactive Controls, the 10 things you can do as a developer to make your application secure. In the previous post, I explained why Parameterized Database Queries are so important in protecting applications from SQL injection, one of the most common and dangerous attacks.
SQL injection is only one type of injection attack. Stopping SQL injection is easy. Stopping other kinds of injection attacks – LDAP injection, XML injection or XPath injection, OS Command injection, and especially Javascript injection (aka Cross Site Scripting} – takes a lot more work. And stopping NoSQL injection – SSJS (Server-Side Javascript) injection and Schema Injection attacks against NoSQL databases – is something that we’re still learning how to do.
Stopping Injection Attacks
The solution to injection attacks is simple in concept: if you can’t clearly separate code from data (which is what you do to prevent SQL injection using a parameterized API), you have to make the data safe before handing it off to an external interpreter (such as an XML parser or an OS command shell or a browser).
You can – and should – try to do this by editing the data on input: rejecting any data that isn't considered safe. But there are limits to how many problems you can catch in input validation, especially if you need to accept and allow free-format text.
So to be safe you have to output encode or escape data before handing it to the interpreter, so that the interpreter will not recognize any executable statements in the data.
The devil is in the details: you need to understand the encoding or escaping rules for each interpreter, and you need to apply the encoding rules correctly in specific contexts (and make sure that you don’t encode data more than once). Browsers make this especially difficult, forcing you to know how and when to encode data properly in different HTML, Javascript, XML and CSS contexts. It’s not enough just to HtmlEncode data:
HTML entity encoding is okay for untrusted data that you put in the body of the HTML document, such as inside a <div> tag. It even sort of works for untrusted data that goes into attributes, particularly if you're religious about using quotes around your attributes. But HTML entity encoding doesn't work if you're putting untrusted data inside a <script> tag anywhere, or an event handler attribute like onmouseover, or inside CSS, or in a URL. So even if you use an HTML entity encoding method everywhere, you are still most likely vulnerable to XSS. You MUST use the escape syntax for the part of the HTML document you're putting untrusted data into.
OWASP XSS (Cross Site Scripting) Prevention Cheat Sheet
There are tools to help you do this: OWASP’s ESAPI encoders (for CSS escaping, HTMLEntity encoding, URL encoding and Javascript escaping, as well as Unix escaping, Windows encoding, VBScript escaping, LDAP encoding, and XML and XMLAttribute and XPath encoding), the OWASP Java Encoder for XSS protection, and Microsoft’s open source Anti-XSS Library for .NET (encoder functions for XSS protection have been taken from this library, improved on and implemented in the .NET 4.5 AntiXssEncoder class).
But even with these tools, it can be difficult to get everything right, which is why injection, especially XSS, is one of the most common major security vulnerabilities in web applications. (To learn more about how XSS works and how to find it in an app, try playing the Google’s XSS game).
CSP – a different approach to stop XSS
A completely different – and simpler – approach to protecting your web app against XSS, especially if you are building a new web app from scratch, is by establishing strong Content Security Policy rules to restrict valid sources for scripts and other resources (connections, images, media, frames…), and to block inline scripting (you will need to structure your Javascript accordingly).
Content-Security-Policy: script-src ‘self’
This HTTP header is all that you need. Of course, this comes with caveats: there are a few edge cases that may not be handled by Content Security Policy restrictions, the Content-Security-Policy header is only implemented in newer browsers (although it is backwards compatible), and you’re depending on the browsers to implement the rules correctly so your app will still be vulnerable to browser bugs.
Watch Jim Manico, a true appsec rock star, explain the Top 10 Proactive Controls. If there is anything that you disagree with, or think is missing in this Top 10 list, please take the time to comment.
Next: input validation. Simple. Obvious. And often done wrong.
1 comment:
CSP seems almost useless for the typical user whose browsing experience has a large number of inclusion to support various value added features for them. We are swamped by logs of blocked scripts and the Human Factors team says we have to permit them all for the sake of the user's expectation.
Post a Comment