1

This is similar to this question, but a bit more specific.

TL;DR; Are there any security concerns with allowing user-provided relative URLs in the Location: header on redirect?

Background:

I'm writing a small proxy for use in front of CouchDB. To authenticate to the CouchDB API, one must submit a POST to the /_session endpoint as described here.

This endpoint takes an optional query parameter, next, which, when present, will cause a successful authentication request to respond with 302 and a Location: redirect, rather than a simple 200.

Now CouchDB has what appears to me to be an insecure implementation of this. The next value is simply appended to the server hostname (with no slash!!). So a request like this:

POST /_session?next=foobar

Will get a response which includes:

Location: http://someserver.comfoobar

I think this is pretty clearly bad, but at least the damage is only limited to authenticated requests, so a random phisher probably can't do a lot with it. But it still makes me a bit uneasy.

So it seems to me that some validation needs to be done. At minimum, a / should be pretended to the user-provided URL. But I'm thinking a simpler approach might be to simply validate that the user-provided URL is relative, and then just respond with that alone.

So for my example:

POST /_session?next=foobar

Would respond with:

Location: /foobar

Is this a safe approach?

1

Letting your site redirect to another URL determined by user input is only considered a vulnerability if it can be used to redirect the user off-site.

Unsafe redirects can be used in phishing attempts: in a phishing email a link to https://realbank.com/?next=http://evil.attacker will have a greater chance to be followed than a link to http://evil.attacker.

Also, unsafe redirects can be used to bypass CSP. If a site has a CSP rule that says it can only load Javascript from that host, loading a page that redirects to script on another host will still work.

Again, these vulnerabilities assume that you can redirect off-site. If you limit the redirects to your own site it is generally safe.

1

There are other dangers of this approach. It really does sound like the CouchDB code is terribly insecure (which doesn't surprise me in the least; I've never seen a NoSQL DB with tolerable security except for things like DynamoDB).

In addition to the danger you've already recognized (redirecting to another domain by abusing the lack of a root path / character), there's also a risk of header injection. If the server just takes the query parameter and appends it without any kind of validation, then an attacker could potentially inject newlines followed by additional HTTP headers, or even a blank line followed by an HTTP response (such as an HTML document). The impact of these things would be dependent on the client - for example, a response with two Location: headers is non-compliant but most clients would follow one of them, and if it's the second one then your attacker has a fully-arbitrary redirect - but I can think of some ways it could almost certainly be exploitable.

The standard solution for open redirects is, if possible, to create a lookup table of destinations and have the request specify the index of that table. That only works if you have a finite (and at least somewhat predictable) number of possible destinations, but is easy to implement and not vulnerable to the kind of shenanigans we're talking about here. It also needn't be an actual lookup table; things like ?next=userprofile,privacysettings or similar (to specify that the user should be redirected to their profile's privacy settings page) work just as well as indexed lookups so long as you validate the supplied strings and don't do anything silly when encountering unrecognized ones.

  • there's also a risk of header injection. Good call. I just tested, and indeed, CouchDB has this vulnerability (at least with version 1.6.1) – Flimzy Mar 12 '17 at 12:11
1

Open Redirect

Where does the next value originally come from? POST requests are not generally vulnerable to open redirect.

But assuming that it is controllable by a previous GET request:

Your approach solves one problem. Before, an attacker could inject .evil.com and thus be redirected to someserver.com.evil.com which is under the control of the attacker. Even if . is not allowed, if the url is eg someserver.co an attacker could inject m and be redirected to someserver.com.

Your solution introduces a new problem though. If an attacker injects /evil.com they will be redirected to //evil.com, which is a protocol-relative URL.

Other Issues

Appart from open redirect issues, being able to internally redirect isn't of too much benefit for an attacker. If the authentication is open to CSRF, it may provide some benefit in login-CSRF attacks (eg to redirect the victim to a page that contains some XSS payload). It may also be possible to bypass referer-check based CSRF protection for GET requests.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.