Background
I'm trying to better understand potential XSS attack scenarios. I understand if you are retrieving data component 'unknow_data' from a server and not validating it the following scenarios could allow malicious code to run.
<script src = unknow_data >
or
<a href=unknow_data></a>
Where unknow_data could be 'javascript:somethingMalicious' instead of pure data.
Question
Is there any threat of XSS when passing unknown data directly into a JavaScript object and not a script tag or html attribute? For example:
var G = unknow_data;
What javascript code, if any, would have to be injected into a plain javascript object for it to be a security risk? My thinking so far is that this is only a threat if you are calling
eval(G)
Is my understanding correct?
It would definitely be a security hole.
Example, the unknown_data could be 1; alert('xss').
However, if you JSON encoded it using your server-side language, it would be safe to print it there (however it may have encoded attacks in it - deal with it like you normally would depending on its context).
It depends on what you do with G.
Certainly eval-ing it would be problematic, but why would you do that anyway?
In addition to the attack mentioned by #alex, if you insert in into the DOM in one way or another, then that's another attack surface.
You should HTML-escape it before inserting it into the DOM, either on the server or the client. If you are using a templating language like Handlebars, then {{G}} will take care of the HTML escaping for you. You need to be cautious with the triple-mustache ({{{G}}}), which skips the HTML escaping.
Related
Let's say you have a javascript with a variable like this:
<script type="text/javascript" >
...some javascript...
var secret = 123;
...some javascript...
</script>
Assuming you're able to write this javascript on the server side. Is it possible to prevent it from being scraped using regular expressions or Xpath?
I'm already changing the variable name on the server side to a random variable name.
The goal here is not to defeat a human taking the time to digest my code and make amendments on the client side (I know I can't stop this). It's more to make it hard/impossible for automated scripts to grab variables. Humans, given enough time, are better at scraping code than machines.
The short answer is no.
The slightly longer answer is that the variable's value will always be transmitted in plaintext to the browser and, therefore, can always be scraped from the JavaScript because it will be declared (or used) in a predictable* manner.
The only bit you, as a creator, can control is making it difficult to programmatically extract. This might be by changing the location and form of the value/secret on every page load in a random manner, making any tokens single-use only, and by encrypting/encoding* things.
This doesn't prevent access to the secret, just makes it less easy to do, and by how much depends on the level of access the user has to the browser. Once you accept this, it boils down to a cost/benefit analysis of how much effort you want to put into this compared to the benefit.
*If the value is encoded in some way, there will be a decoding function within the JavaScript, enabling the encoded variable to be passed into the decoding function. Or perhaps any functions can be replaced. For further reading, have a look into the very few attempts at encryption/decryption in JavaScript.
I've been doing some experimenting with innerHTML to try and figure out where I need to tighten up security on a webapp I'm working on, and I ran into an interesting injection method on the mozilla docs that I hadn't thought about.
var name = "<img src=x onerror=alert(1)>";
element.innerHTML = name; // Instantly runs code.
It made me wonder a.) if I should be using innerHTML at all, and b.) if it's not a concern, why I've been avoiding other code insertion methods, particularly eval.
Let's assume I'm running javascript clientside on the browser, and I'm taking necessary precautions to avoid exposing any sensitive information in easily accessible functions, and I've gotten to some arbitrarily designated point where I've decided innerHTML is not a security risk, and I've optimized my code to the point where I'm not necessarily worried about a very minor performance hit...
Am I creating any additional problems by using eval? Are there other security concerns other than pure code injection?
Or alternatively, is innerHTML something that I should show the same amount of care with? Is it similarly dangerous?
tl;dr;
Yes, you are correct in your assumption.
Setting innerHTML is susceptible to XSS attacks if you're adding untrusted code.
(If you're adding your code though, that's less of a problem)
Consider using textContent if you want to add text that users added, it'll escape it.
What the problem is
innerHTML sets the HTML content of a DOM node. When you set the content of a DOM node to an arbitrary string, you're vulnerable to XSS if you accept user input.
For example, if you set the innerHTML of a node based on the input of a user from a GET parameter. "User A" can send "User B" a version of your page with the HTML saying "steal the user's data and send it to me via AJAX".
See this question here for more information.
What can I do to mitigate it?
What you might want to consider if you're setting the HTML of nodes is:
Using a templating engine like Mustache which has escaping capabilities. (It'll escape HTML by default)
Using textContent to set the text of nodes manually
Not accepting arbitrary input from users into text fields, sanitizing the data yourself.
See this question on more general approaches to prevent XSS.
Code injection is a problem. You don't want to be on the receiving end.
The Elephant in the room
That's not the only problem with innerHTML and eval. When you're changing the innerHTML of a DOM node, you're destroying its content nodes and creating new ones instead. When you're calling eval you're invoking the compiler.
While the main issue here is clearly un-trusted code and you said performance is less of an issue, I still feel that I must mention that the two are extremely slow to their alternatives.
The quick answer is: you did not think of anything new. If anything, do you want an even better one?
<scr\0ipt>alert("XSSed");</scr\0ipt>
The ground, bottom line is that there are more ways to trigger XSS than you think there is. All the following are valid:
onerror, onload, onclick, onhover, onblur etc... are all valid
The use of character encoding to bypass filters (null byte highlighted above)
eval falls into another category, however - it is a byproduct, most of the time to obfuscate. If you're falling to eval and not innerHTML, you're in a very, very small minority.
The key to all this is to sanitize your data using a parser that keeps up to date with what pen testers discover. There are a couple of those around. They absolutely need to at least filter all the ones on the OWASP list - those are pretty much common.
innerHTML isn't insecure in and of itself. (Nor is eval, if only used on your code. It's actually more of a bad idea for several other reasons.) The insecurity arises in displaying visitor-submitted content. And that risk applies to any mechanism with which you embed user-content: eval, innerHTML, etc. on the client-side, and print, echo, etc. on the server-side.
Anything you put on the page from a visitor must be sanitized. It doesn't matter a great deal whether you do it when the initial page is being built or added asynchronously on the client-side.
So ... yes, you need to show some care when using innerHTML if you're displaying user-submitted content with it.
How can I stop script from execution in JavaScript? In case of cross-site scripting (XSS) attacks, the fundamental requirements are injection + execution of script.
Imagine a scenario where attacker is able to inject JavaScript in a page & our goal is to stop attacker's script from execution. The injection point as an example can be any user-supplied input area.
Always always escape your input. For XSS, use htmlentities() to escape HTML and JS. Here's a good article on PHP Security
http://www.phpfreaks.com/tutorial/php-security
There are basically two things to be careful of when dealing with XSS:
Escape your output. Escaping the input just takes more resources for nothing. Escape your user-submitted content output. It also means that non-escaped content is in your database, which is a good thing (in case of false positives you can fix that without losing content, in case of a new XSS policy you don't need to modify all your database, etc).
Secure your javascript code. Be very careful not to include some flaw using eval() or something like it.
As others said, the best and easiest way to protect yourself from XSS is validating input and properly escape output depending on the insertion point (HTML, most likely, with entities or JavaScript / CSS blocks -- unlikely and more difficult to properly escape).
However, if your use case is outputting raw user input which is supposed to contain arbitrary HTML and you just want to prevent injected JavaScript to mess with your site, you can either:
1) Frame the content in a different, unique domain (so it cannot share cookies with your main document), e.g. xyz123.usercontent.com (with xyz123 different for any user)
2) Wait for and/or CSP's sandbox directive to be standardized in every browser you support (and, of course, denying access to uncapable browsers).
Your only solution is to prevent scripts from being injected. There's several things you can do to achieve this:
Never trust input from the user. That means form inputs, query string parameters, cookie content, or any other data obtained from an incoming request.
Sanitize everything you render, everywhere you render it. I like to achieve this with two clearly-named rendering functions in templates, render and render_unsafe. Rails has a similar interface since 3.0 which sanitizes all template data unless you specifically ask for unsanitized rendering. Having a clearly-named interface will make it easier to keep your templates in check, and ensuring that unsanitized renders are the exception forces you to make a decision every time you dump data into a template.
If you must allow the user to run functions directly, always do it through a whitelist. Have them supply a function name or some other identifier as a string and their arguments as JSON or some other parseable construct. Have a look at the design for Shopify's Liquid templating system which uses a similar execution-safe whitelisting pattern.
Never trust input from the user. Not ever.
As far as I know it is considered bad practice to eval() JSON objects in JavaScript, because of security. I can understand this concern if the JSON comes from another server.
But if the JSON is provided by my own server and is created using PHP's json_encode (let us assume it is not buggy), is it legitimate to simply use eval() to read the JSON in JS or are there any security problem I currently can't think of?
I really don't want to deal with dynamically loading a JSON parser and would be glad to simply use eval().
PS: I will obviously use the native JSON object if it is available, but want to fall back to eval() for IE/Opera.
In your scenario, the question becomes, where is PHP getting the javascript to execute from? Is that channel secure, and free from potential user manipulation? What if you don't control that channel directly?
There are a number of ways that your security may be compromised.
Man in the middle attacks could theoretically alter the contents of data being delivered to the client.
Your server traffic could be intercepted elsewhere and different content could be provided (not quite the same as a MIM attack)
Your server could be compromised and the data source could be tampered with.
and these are just the simple examples. XSS is nasty.
"an ounce of prevention is worth a pound of cure"
Besides the obvious security issues:
Native JSON is faster
You don't need to "load" a JSON parser it's just another function call to the JavaScript engine
Tip:
in asp.net using JSON is considered bad becuase parsing of DateTime differs between the server and the client so we use a special function to deserialize the date in javascript. I'm not sure if PHP has the same issue but its worth mentioning though.
check out this:http://blog.mozilla.com/webdev/2009/02/12/native-json-in-firefox-31/
so at least for firefox you can use the built in json parser
Seriously? Some of the guys here are paranoid. If you're delivering the JSON and you know it's safe, it's ok to fallback(*) to eval(); instead of a js lib for IE. After all, IE users have much more to worry about.
And the man-in-the-middle argument is bullsh*t.
(*) the words fallback and safe are in bold because some people here didn't see them.
I'm new to ColdFusion, so I'm not sure if there's an easy way to do this. I've been assigned to fix XSS vulnerabilities site-wide on this CF site. Unfortunately, there are tons of pages that are taking user input, and it would be near impossible to go in and modify them all.
Is there a way (in CF or JS) to easily prevent XSS attacks across the entire site?
I hate to break it out to you, but -
XSS is an Output problem, not an Input problem. Filtering/Validating input is an additional layer of defence, but it can never protect you completely from XSS. Take a look at XSS cheatsheet by RSnake - there's just too many ways to escape a filter.
There is no easy way to fix a legacy application. You have to properly encode anything that you put in your html or javascript files, and that does mean revisiting every piece of code that generates html.
See OWASP's XSS prevention cheat sheet for information on how to prevent XSS.
Some comments below suggest that input validation is a better strategy rather than encoding/escaping at the time of output. I'll just quote from OWASP's XSS prevention cheat sheet -
Traditionally, input validation has been the preferred approach for handling untrusted data. However, input validation is not a great solution for injection attacks. First, input validation is typically done when the data is received, before the destination is known. That means that we don't know which characters might be significant in the target interpreter. Second, and possibly even more importantly, applications must allow potentially harmful characters in. For example, should poor Mr. O'Malley be prevented from registering in the database simply because SQL considers ' a special character?
To elaborate - when the user enters a string like O'Malley, you don't know whether you need that string in javascript, or in html or in some other language. If its in javascript, you have to render it as O\x27Malley, and if its in HTML, it should look like O'Malley. Which is why it is recommended that in your database the string should be stored exactly the way the user entered, and then you escape it appropriately according to the final destination of the string.
One thing you should look at is implementing an application firewall like Portcullis: http://www.codfusion.com/blog/page.cfm/projects/portcullis which includes a much stronger system then the built in scriptProtect which is easily defeated.
These are a good starting point for preventing many attacks but for XSS you are going to end up going in by hand and verifying that you are using things like HTMLEditFormat() on any outputs that can be touched by the client side or client data to prevent outputting valid html/js code.
The ColdFusion 9 Livedocs describe a setting called "scriptProtect" which allows you to utilize coldfusion's protection. I've have not used it yet, so I'm not sure how effective it is.
However, if you implement a third-party or your own method of handling it, you would most likely want to put it in the "onRequestStart" event of the application to allow it to handle the entire site when it comes to URL and FORM scope violations (because every request would execute that code).
Besides applying all the ColdFusion hot fixes and patches you can also:
Not full proof but helps, Set the following under CFADMIN > Settings > "Enable Global Script Protection"
Add CSRFToken to your forms http://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet
Check http Referer
Add validation for all User inputs
Use cfqueryparam for your queries
Add HTMLEditFormat() on any outputs
Besides Peter Freitag's excellent blog you should also subscribe to Jason Dean's http://www.12robots.com