Friday, 29 April 2011

XSS myths: input validation is not enough!

Do you still believe input validation is enough to fix Cross Site Scripting (XSS)?

Billy Hoffman said it best at Schmoocon 2007 (4 years ago!!!) in his talk "JavaScript Malware for a Grey Goo Tomorrow" (fast forward to Q & A, minute 51:45):

Person in the audience asks: "You said that AJAX doesn't really change security ..."

Billy Hoffman: "No, it does ... yes"

Person continues: "It doesn't change the fact that the root cause is still input validation since it sucks on everything ..."

Billy Hoffman (roughly exact quote, he talks really fast!): "Certainly, well, I don't want to be .. everyone wants to think ... oh .. web security is nothing new, it's input validation, right? well there has not been anything new in security in the last 30 years, right? it's all input validation, it's all configuration, I mean, I've got a book that's called 'Security and Privacy in computing systems' it is written by this dude in MIT from 1973 and in it he talks about pretty much everything before it became popular, he talks about having a centralised system for vulnerability management reporting, he talks about having to develop tiger teams because it is the only way you are going to find out whether your security is breaking, he talks about input validation back in the day when the computer was so expensive that if a grad student crashed it it was worth more than the grad students' life and that's why you did input validation because you wanted to make sure your program didn't get junked getting crashed, I mean, I don't mean to come down on you but none of this is new, right? it's simply how these things apply to different types of paradigms, right? in the web for example, input validation takes a much bigger role, right? if I open 5000 pipes into word and it crashes ... who cares? right? even if it is a buffer overflow, why would I do that to execute code as myself? that's silly. But if I can do that to a Google document and sheets and I own the server I win, so it is all about how these things apply to different types of situations"

Well, it is now 2011 and you would be surprised but some people, even in the security industry still believe that input validation is a valid fix for Cross Site Scripting! This group of people includes but is not limited to:

- Some people that attend security conferences (I did not hear it at BSides London though! :))
- Some people that put together and/or approve questions for top-notch security certifications (who will remain nameless)
- Some people that are employed by the most reputable security companies in the industry (who will remain nameless too)

I mean, if input validation was a valid fix ... why on earth is it not even mentioned in the OWASP Cross Site Scripting Prevention Cheat Sheet? Look at the XSS prevention rules there, it is all about being careful when rendering untrusted data and how to escape it/output encode it depending on where it is rendered on the page:

- 2.7 RULE #6 - Use an HTML Policy engine to validate or clean user-driven HTML in an outbound way (output stripping, not input validation for special cases where you have to allow HTML by design)
- 2.8 RULE #7 - Prevent DOM-based XSS (output encoding, not input validation)


If you tried to fix Cross Site Scripting and "input validation" was all you did you have a serious problem, at a minimum your application is still possibly vulnerable to Cross Site Scripting of the worst kind aka Stored Cross Site Scripting.

I will go as far as saying this:

Input validation (or even worse fully relying on restricted charsets, which I won't get into) in the context of Cross Site Scripting is the network security equivalent of changing a vulnerable SSH service from port 22 to port 12345. Yes, port 22 is no longer available but you can still get compromised via port 12345 (that granted, will be a bit harder to spot for automated botnets and you will definitely get a lot less scan attempts there but it is not a full fledged fix)

Please consider the following scenarios:

You relied on input validation as the only layer of defense against Cross Site Scripting and any of the following happens:

- User input is rendered in an attribute and the customer now wants to allow double quotes in the company name field so they can type in company names like 'Joe "The biker"'
- User input is rendered in a text area and the customer now wants to allow angle brakets and other characters that may allow for cross site scripting
- I did this in a web application pen test some time ago: JavaScript using user input could be uploaded via an XML file, the name was "validated" by the .NET Validate Request built-in feature when the field was updated in the normal form but it could see nothing when I uploaded the field with script tags HTML encoded so that the XML did not break in the upload parsing process ....
- A third party application that modifies and injects scripts into your database could be interacting with the application you built in a few months/years down the line
- A user allowed to access the database (i.e. malicious DBA, developer or Administrator) inserts a hidden script in a field that is going to be rendered to all users in the home page, if this script starts with a bunch of newline characters it could well go undetected for years.
- Another host in the DMZ gets compromised and the clear-text communication between the database and the web server can be intercepted and altered on the fly inserting JavaScript code via man in the middle (MiTM) -altering SQL query results to contain hidden scripts, for example-
- Etc

If any of the above happened the only reason your application would render malicious JavaScript is simply because Cross Site Scripting was never fixed in the first place. Input validation is not enough for this: data can get into the database in so many ways you must treat it as hostile and output encode it as if it was directly submitted from a form in your site. You can argue that you have worse problems than Cross Site Scripting if some of those scenarios happen, but the situation is really that you would have those worse problems plus Cross Site Scripting, thanks to your application, which was never coded correctly. Changing business requirements for input validation is not rare either ..


In my experience very few companies would take the time to review where the output of a field is rendered, and if it is correctly output encoded there, if the new business requirement was just changing the validation rules to allow for cross site scripting-friendly characters. And in fact, there would be no reason to do this if the field was correctly output encoded in the first place


Therefore, if input validation was all you did your application is probably vulnerable and just waiting for a disaster to happen.

Input validation, like changing a port to a non-default port, has its place in the context of cross site scripting only as an additional layer of defense but never as a valid full fledged fix!
You do not have to take my word for it, OWASP explain it themselves on their site:

How Do I Prevent XSS?

Preventing XSS requires keeping untrusted data separate from active browser content.
1. The preferred option is to properly escape all untrusted data based on the HTML context (body, attribute, JavaScript, CSS, or URL) that the data will be placed into. Developers need to include this escaping in their applications unless their UI framework does this for them. See the OWASP XSS Prevention Cheat Sheet for more information about data escaping techniques.

2. Positive or “whitelist” input validation is also recommended as it helps protect against XSS, but is not a complete defense as many applications must accept special characters. Such validation should decode any encoded input, and then validate the length, characters, and format on that data before accepting the input.

3. Consider employing Mozilla’s new Content Security Policy that is coming out in Firefox 4 to defend against XSS.