10

Say you have a web site and you are using some returnUrl URL parameter to redirect user back to page where he was after login or editing some records in user area. Is there some standard way how to check if the returnUrl is located on same server as the web application?

So far I figured out, that there are two ways how atacker can redirect user elsewhere and following actions can be performed to prevent these attacks:

  1. Attacker supplies whole URL in the parameter (http://evil.com/) - here it is possible to check if parameter contains http(s):// or ftp://
  2. Browser automatically adds the protocol if it is missing, so attacker can provide something like //evil.com or //numeric_ip_address and it will redirect user outside the server too - here you can still check if URL starts with the //

Are there any other ways to encode URL address? Can I be sure that the parameter cannot be misused if I check only previous two cases?

AviD
  • 72,138
  • 22
  • 136
  • 218
bretik
  • 1,840
  • 13
  • 22
  • there are additional ways to obfuscate the address, such as htp:// or even ht:// or hp://. It can be encoded, the site can be given as DWORD, and there are more. – AviD Nov 22 '10 at 12:36

4 Answers4

6

One way you could approach this would be to encrypt the parameter as it's passed to the user with a key stored on the server (also for better protection consider adding a HMAC). Then when the user submits the form, decrypt the parameter (and check the HMAC if used) and use it to redirect the user.

I've seen cases where the URL is just obfuscated (base64 encoding etc). That might deter casual attackers, but I wouldn't rely on it, as a determined attacker is likely to work out the scheme used.

Rory McCune
  • 60,923
  • 14
  • 136
  • 217
  • This is a good suggestion, but in this situation we need data authentication, not encryption. HMAC is a good suggestion. However, [encryption doesn't provide data authentication](http://security.stackexchange.com/a/2206/971) (in general), and so encryption alone is not sufficient. – D.W. Feb 20 '12 at 01:20
4

You can add your website's prefix onto the url so they would go to:

example.com/login.php?returnurl=profiles/home.php

And in the page you would have it return to http://example.com/ and add of the return URL. (http://example.com/RETURNURLHERE)

James T
  • 1,853
  • 1
  • 17
  • 26
  • 2
    I personally like this approach. Solves the problem, and the added benefit of a shorter and cleaner and more readable URL. – 700 Software Dec 23 '11 at 15:05
2

There are many ways to attack a user/browser or obfuscate URLs/redirects. Crazy way's that will make your brain hurt and leave you asking why does that work?! (see: http://code.google.com/p/browsersec/) In general, when validating input, don't try to fix the data, if its not what you expected or not in the format you required, throw it away. Remember default deny, this is just another example of that.

Like anything, how you implement this, is dependent on your requirements. You also should be aware of implementation flaws when handling redirects that can also open up further vulnerabilities such as HTTP response splitting, Header injection, etc.

I usually recommend a combination of destination whitelisting and request signing (using HMAC, similar to Rory's suggestion). When preforming request signing, I like to make the destination visible in the URI. For example:

http://yoursite.com/login.php?returnurl=welcome.php&hash=yourlonghashhere

That allows the user to have a little viability into where the request should go, and also allows for more savvy users to possibly notice a phishing or other attack on their own.

When a redirect is about to occur:

  1. Verify the 'returnurl' against the hash
  2. Verify the 'returnurl' is whitelisted
  3. Then preform the redirect.

If any step of the validation process fails, either redirect to a default/home page or reject the request.

Here are some more resources:

Gerry
  • 366
  • 1
  • 4
0
  1. Remove all unnecessary information from the URL (e.g. http://, the name of the site, etc.). If you have several options (e.g. five sites), use their index.
  2. Calculate a hash of what remains using a server-side secret salt and prepend it (or a part of it - the shorter it is, the greater the danger of a successful collision attack) to returnUrl
  3. Upon receiving the returnUrl, check the hash is valid. If not, reject.
  4. Add back all missing information and redirect.

Also, some redirects may follow a common pattern where you only need to plug some parameters in. In this case you might not even need the hash.

For example: instead of

returnUrl=http://www.myfifthsite.com/common/webpage/profile?user=lserni

you can boil the

returnUrl=5-5-lserni

meaning fifth site, 5th allowed redirect pattern, this pattern has only one parameter and its value is the username:

sites: ... 5 => 'http://www.myfifthsite.com' ...

patterns for site #5 (of course authentication is not overridden!): 5 => '/common/webpage/profile?user=$1' 6 => '/common/webpage/messages?user=$1'

An attacker could enumerate all allowed site and pattern numbers, but would only get valid URLs of the sites you allow.

So in a sense, this way you need check nothing at all. The URLs will always be automatically valid (even if some might still require authentication cookies).

LSerni
  • 22,521
  • 4
  • 51
  • 60