Ensuring path based redirects

23 views
Skip to first unread message

André N. Klingsheim

unread,
Feb 23, 2021, 5:45:28 PM2/23/21
to Security-dev
I came across an interesting aspect of URLs and redirects. If you redirect with the following location header, it redirects to google.com

Location: //google.com

Which wasn't intuitive, but probably makes sense according to the spec, since this is a URL with an authority segment.

There is a fine line here between that and /google.com, which would be a redirect to a different path on the same origin. A naive security check for whether a URL starts with "/" would therefore fail miserably.

Is there a safe and easy way to check if a URL represents a path and therefore would be safe for redirect? E.g. check that the URL starts with a single "/".

Thanks in advance for any input.

Best,
André

Chris Palmer

unread,
Feb 23, 2021, 5:58:06 PM2/23/21
to André N. Klingsheim, Security-dev
Hi André,

I think the key thing here is never to use lexical matching (regular expressions, looking for substrings/prefixes/suffixes, et c.), but to use a true parser. Python's URL parser, for example, makes the difference clear:

~ $ python3 -q
>>> from urllib.parse import urlparse
>>> urlparse("/google.com")
ParseResult(scheme='', netloc='', path='/google.com', params='', query='', fragment='')
>>> urlparse("//google.com")
ParseResult(scheme='', netloc='google.com', path='', params='', query='', fragment='')

Your decision-making code should operate on your language's/library's equivalent of a ParseResult, not on a string.

I hope this helps!

Andre N. Klingsheim

unread,
Mar 1, 2021, 6:28:09 PM3/1/21
to Chris Palmer, Security-dev
Hi Chris,

Thank you for your swift response and sorry for the tardy response. 

That's good advice, unfortunately in this particular case there was very limited help for dealing with relative URIs in the .NET parsing libraries so I had to look for alternatives. This is a slippery slope, having a look at the last comment in 4.2, I poked around with that example: https://tools.ietf.org/html/rfc3986#section-4.2

>>> from urllib.parse import urlparse
>>> urlparse("http:google.com")
ParseResult(scheme='http', netloc='', path='google.com', params='', query='', fragment='')
>>> urlparse("https:google.com")
ParseResult(scheme='https', netloc='', path='google.com', params='', query='', fragment='')

I have an app that returns a 302 from http://localhost:54103/Home/Redirect2

The following two location headers behave very differently in Chrome (88)

Location: https:google.com -> https://google.com

It seems inconsistent, is that intended behaviour or is it perhaps a bug?

When it comes to libraries for URL parsing, it's true what they sing. ♫ I still haven't found what I'm looking for ♫

There also seem to be a bit of discussion about this for other platforms, so I unfortunately don't think this is that straight forward in practice: https://github.com/golang/go/issues/27650

Best,
André

Chris Palmer

unread,
Mar 1, 2021, 9:00:18 PM3/1/21
to Andre N. Klingsheim, Security-dev
Interesting! I wrote up some quick test cases to try to see if we have a bug at all similar to the Go bug you linked to, but it seems like we don't. (So far. Maybe better test cases would turn something up.)

There might (or might not?) be a bug or quirk in the part of the code that interprets the output of the URL parser when computing redirects; I'll run this by some people who might know.

I'd say go ahead and file a bug in any case. Let us know what bug number you get, and I'll make sure the right people are CC'd on it.
Reply all
Reply to author
Forward
0 new messages