views:

34

answers:

1

I'm getting a string from the current window's fragment identifier (location.hash). I want to use that string as the argument to location.replace(str).

Under normal circumstances, the string will come from code I control, so I'm not worried about validating that the string is a URL. If the string isn't a URL, the call to replace will just fail. That's fine.

What I am concerned about is making sure the string is NOT a javascript: URL or anything else that would allow someone to run arbitrary Javascript on my domain. Currently, I'm just checking that that str.indexOf('http') == 0.

Is that enough or should I sanitize this string some more?

A: 

The sanitization you propose is not enough.

An attacker could redirect to a data:uri url that contains base64 encoded html/javascript. This would allow the attacker to execute arbitrary javascript code. For example, this code snippet will alert 'xss' (in firefox, safari and opera)


    var data = 'data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik8L3NjcmlwdD4=';
    location.replace(data);

Besides, it may be possible to redirect to a anonymous FTP url, or use some other obscure protocol.

Instead of blacklisting protocols/keywords, use a whitelist approach instead. Maintain a list of good urls in your javascript code. Then, read the fragment identifier and see if it is in this known list of urls. If it is not, stop the process.

In security, whitelists are always preferable to blacklists.

sri
Your example data string wouldn't pass the test I've proposed because it doesn't start with 'http'. I don't think I need to worry about redirects either. I'm only trying to prevent unauthorized Javascript from running in the context of my domain.
Brian
Well, your code tests for `indexOf` http and not startswith http. If the attacker puts http somewhere in the payload, your test would pass, and the attacker would still be able to execute javascript code.
sri
str.indexOf('http') == 0 is equivalent to startsWith.
Brian