Subject: [OAUTH-WG] WRAP session fixation?

From: Brian Eaton <[email-masked]>
Date: Tue, 24 Nov 2009 17:28:41 -0800

On Tue, Nov 24, 2009 at 4:35 PM, Mike Malone <[email-masked]> wrote:
> One final note - unless I'm missing something WRAP is vulnerable to
> the same session fixation attack that OAuth 1.0 had... unless it's
> requiring callback registration, which is a really lame solution to
> that problem.

Callback registration is not required to prevent session fixation.
Check out the requirements in section 5.4.6 "Successful Access Token
Response From Authorization Server."  They are (supposed to) be
sufficient to prevent the attack.

Cheers,
Brian

---

From: Michael Malone <[email-masked]>
Date: Tue, 24 Nov 2009 17:45:01 -0800

> sufficient to prevent the attack.

Ah interesting, so you pass the callback URL to the authorization  
server again to get an access token? How does that work if you _do_  
have a registered callback URL? I'll have to take another look at the  
spec.

Thanks,
Mike

---

From: Brian Eaton <[email-masked]>
Date: Tue, 24 Nov 2009 17:58:35 -0800

On Tue, Nov 24, 2009 at 5:45 PM, Michael Malone <[email-masked]> wrote:
> Ah interesting, so you pass the callback URL to the authorization server
> again to get an access token? How does that work if you _do_ have a
> registered callback URL?

It depends on the authorization server, but my guess is that if the
authorization server required callback URL registration in the first
place they will be checking callback URLs when users hit the approval
page.  If an unknown callback URL hits the approval page, the
authorization server will probably refuse to return the user to the
callback.

Cheers,
Brian

---

From: Brian Eaton <[email-masked]>
Date: Tue, 24 Nov 2009 18:17:54 -0800

On Tue, Nov 24, 2009 at 6:14 PM, Luke Shepard <[email-masked]> wrote:
> Yup, that’s basically what we do today- throw an error and don’t return. But
> this is less than ideal.
>
> We have discussed that we’d probably like to return, but with an error
> message. This would be in section 5.4.4 of the spec (“Authorization server
> directs user back to the client”) we would like to pass additional
> parameters for the error message- something other than user_denied, but
> which indicates that the application was just misconfigured.

I guess it depends on the business requirements that led to callback
URL preregistration.  Some sites require callback URL registration so
they don't need to redirect to unknown third-party sites... in which
case redirecting with an error message doesn't really fix the issue.

Other sites require callback URL registration for security reasons, in
which case an error message is just fine.

Cheers,
Brian

---

From: Luke Shepard <[email-masked]>
Date: Tue, 24 Nov 2009 18:14:45 -0800

Yup, that's basically what we do today- throw an error and don't return. But this is less than ideal.

We have discussed that we'd probably like to return, but with an error message. This would be in section 5.4.4 of the spec ("Authorization server directs user back to the client") we would like to pass additional parameters for the error message- something other than user_denied, but which indicates that the application was just misconfigured.

On 11/24/09 5:58 PM, "Brian Eaton" <[email-masked]> wrote:

Cheers,
Brian

---

From: Brent Goldman <[email-masked]>
Date: Wed, 25 Nov 2009 06:57:17 -0800

Facebook Platform/Connect has some pretty interesting logic involving registered callback URLs in our proprietary auth flows. Much of this is because we hate showing error messages. Maybe OAuth could borrow some of these ideas? Here's some more info.

I'm using the terminology "specified callback URL" to refer to the callback URL specified in the request, and "registered callback URL" to refer to the callback URL configured with us in advance. There are two types of callback URLs that can be specified in a request: absolute and relative.

Case 1. Specified callback URL is absolute.
If the specified callback URL is "safe", we redirect to it. Otherwise, instead of throwing an error, we redirect to the registered callback URL, with the specified callback URL in a GET param called "next". It's up to the developer of the registered callback URL to use the "next" param, or they can just ignore it.

To determine if the specified callback URL is safe: if the registered callback URL is a directory, then the specified callback URL has to be within that subdirectory. Otherwise, the specified callback URL has to point to the same file as the registered callback URL, and any query params on the registered callback URL have to also be present in the specified callback URL

For example, if the registered callback URL is http://www.foobar.com/callback/, and the specified callback URL is http://www.foobar.com/callback/method2, we know the specified callback URL is safe and thus redirect directly there. But if the specified callback URL is http://www.facebook.com/logged-into-foobar, which is unsafe, we redirect to http://www.foobar.com/callback?next={urlencode(http://www.facebook.com/logged-into-foobar)}

Note: we also support the concept of a "base domain", which essentially whitelists every page on that domain, and every page on all subdomains of that domain, as safe.

Case 2. Specified callback URL is relative.
In this case, there's no issue of safety, since we'll always redirect to a URL constructed based on the registered callback URL, which is by definition safe.

More information about constructing the URL to redirect to:
2.1. If the registered callback URL doesn't have a question mark anywhere in it, we can just append the specified callback URL to it and redirect. For example, with a registered callback of http://www.foobar.com/callback/ and a specified callback URL of "loggedin.php?done=true", we redirect to http://www.foobar.com/callback/loggedin.php?done=true.
2.2 If the registered callback URL has a question mark, we append the specified callback URL directly, but do some munging to the params to get everything on the same level. For example, with a registered callback of "http://www.foobar.com/callback?page=" and a specified callback URL of "loggedin.php?done=true", we redirect to http://www.foobar.com/callback?page=loggedin.php&done=true (notice how the second ? changed to a &).

Case 3. Unspecified callback URL.
I lied, there's actually a third case. We support auth flows with unspecified callback URLs in the request. If there's a registered callback URL, we just redirect there. Otherwise, we show an error message. So basically the only way to get an error message is if there is no specified callback URL or registered callback URL.

-Brent

On Nov 24, 2009, at 6:17 PM, Brian Eaton wrote:

On Tue, Nov 24, 2009 at 6:14 PM, Luke Shepard <[email-masked]<mailto:[email-masked]>> wrote:
Yup, that’s basically what we do today- throw an error and don’t return. But
this is less than ideal.

Cheers,
Brian

---

From: Mike Malone <[email-masked]>
Date: Mon, 30 Nov 2009 11:26:35 -0800

Interesting, but presumably if the callback is transferred securely
(e.g., if it's transmitted from the consumer with a signature) none of
this is really necessary. You'd probably want to blacklist some URI
schemes (like javascript:) but other than that as long as you can
verify that the consumer is sending the callback then what's wrong
with assuming it's legitimate?

Of course that doesn't work with Connect, since the browser-based flow
complicates things, but for OAuth I think formalizing more rigorous
rules for validating the callback isn't necessary.

Mike

On Wed, Nov 25, 2009 at 6:57 AM, Brent Goldman <[email-masked]> wrote:
> Facebook Platform/Connect has some pretty interesting logic involving
> registered callback URLs in our proprietary auth flows. Much of this is
> because we hate showing error messages. Maybe OAuth could borrow some of
> these ideas? Here's some more info.
> I'm using the terminology "specified callback URL" to refer to the callback
> URL specified in the request, and "registered callback URL" to refer to the
> callback URL configured with us in advance. There are two types of callback
> URLs that can be specified in a request: absolute and relative.
> If the specified callback URL is "safe", we redirect to it. Otherwise,
> instead of throwing an error, we redirect to the registered callback URL,
> with the specified callback URL in a GET param called "next". It's up to the
> developer of the registered callback URL to use the "next" param, or they
> can just ignore it.
> To determine if the specified callback URL is safe: if the registered
> callback URL is a directory, then the specified callback URL has to be
> within that subdirectory. Otherwise, the specified callback URL has to point
> to the same file as the registered callback URL, and any query params on the
> registered callback URL have to also be present in the specified callback
> URL
> For example, if the registered callback URL is
> http://www.foobar.com/callback/, and the specified callback URL is
> http://www.foobar.com/callback/method2, we know the specified callback URL
> is safe and thus redirect directly there. But if the specified callback URL
> is http://www.facebook.com/logged-into-foobar, which is unsafe, we redirect
> to
> http://www.foobar.com/callback?next={urlencode(http://www.facebook.com/logged-into-foobar)}
> Note: we also support the concept of a "base domain", which essentially
> whitelists every page on that domain, and every page on all subdomains of
> that domain, as safe.
> In this case, there's no issue of safety, since we'll always redirect to a
> URL constructed based on the registered callback URL, which is by definition
> safe.
> 2.1. If the registered callback URL doesn't have a question mark anywhere in
> it, we can just append the specified callback URL to it and redirect. For
> example, with a registered callback of http://www.foobar.com/callback/ and a
> specified callback URL of "loggedin.php?done=true", we redirect to
> http://www.foobar.com/callback/loggedin.php?done=true.
> 2.2 If the registered callback URL has a question mark, we append the
> specified callback URL directly, but do some munging to the params to get
> everything on the same level. For example, with a registered callback of
> "http://www.foobar.com/callback?page=" and a specified callback URL of
> "loggedin.php?done=true", we redirect to
> http://www.foobar.com/callback?page=loggedin.php&done=true (notice how the
> second ? changed to a &).
> I lied, there's actually a third case. We support auth flows with
> unspecified callback URLs in the request. If there's a registered callback
> URL, we just redirect there. Otherwise, we show an error message. So
> basically the only way to get an error message is if there is no specified
> callback URL or registered callback URL.
> -Brent
>