views:

39

answers:

2

In my webapp I'm using HTTP Location: headers for redirect (e.g. POST/redirect/GET). But the target locations have to be dynamic (e.g. login.php?dest=pagexy.php). We all know that any user-modifiable input has to be properly escaped to prevent XSS, so

 header('Location: '.$_REQUEST['dest']);

looks wrong. Simple urlencode-ing can only be used for simple files, not paths (e.g. cross-domain URLs with Single-Sign-On).

I've also read about vulnerabilities like:

Location: javascript:...bad.stuff...  or
Location: data:text/html:base64,...

Having an explicit whitelist of destinations would probably the most secure solution, but is tedious and might even not be possible for all use-cases.

Solutions?

Edit:

  1. Is urlencoding enough/correct for simple files? Assume a recent PHP version (> 5.1.2, AFAIK) that forbids newlines in header().

  2. How can I safely handle cross-domain credential-checking without knowing each other-domain beforehand?

+1  A: 

Simple: DON'T EVER DO THAT.

If you must redirect the user, don't ever let them tell you where they are going.

If you absolutely must do that, urlencode the the input, whitelist the domains, and strip parameters that you haven't whitelisted. Better yet, don't let them tell you what domain - produce that using some other backend switch.

If you don't seriously lock that down, you will be vulnerable to all kinds of things. Be especially careful that they can't put a linebreak in there.

More info:

Paul McMillan
Recent PHP versions filter for newlines in header(), so thats fine. Especially, how can I handle SSO-type use-cases, where I can't know all target domains beforehand?
smilingthax
Pass your application a hash from the originating function, and match that hash to send the header. It sounds like you may be trying to do something that's fundamentally insecure by design, rather than simply technically hard. You should give us specifics about what precisely you want to do.
Paul McMillan
There are different scenarios involved: I currently have two serious flaws in my app, with login and with POST/redirect/GET. I'm now pretty convinced that there is no "Location:"-only solution. Instead I'll have to use fixed redirect targets and/or cookies. OTOH the cross-domain thing is about some local rich client web-apps that support extended functionality when coupled with users remote account on my server-app(which should then also be aware of the local app). AFAICS security demands at least explicit coupling actions by the user, but the devil is in the details. More thinking required.
smilingthax
Yeah, location headers are devilishly hard to get right. Even REALLY MAJOR players screw them up on a fairly regular basis. I really believe that allowing the client to specify anything other than a pre-mapped token for where they want to go is going to be insecure in some way or another. When you figure out your new layout, try posting the procedure here in detail for us to have a look at.
Paul McMillan
+1  A: 

There actually occurs three kinds of attacks:

  1. HTTP Response Splitting, but as mentioned is some the comments, header() filters CRLF symbols.
  2. Open Redirect, which I suppose cannot be mitigated in your case.
  3. XSS. urlencode() is useless, don't bother it. You should make sure URL is http:// (or https://) as long as it's possible to make redirect to javascript: (some browsers allow it, but not all) and data: URIs.

For more information on Open Redirect and its issues see presentation at OWASP AppSec 2010 by sirdarckcat and thornmaker

p0deje