Fix an anchor redirect issue with OAuth server, plus modernize the application a bit
Summary:
Ref T4593. Via HackerOne. An attacker can use the anchor reattachment, combined with the Facebook token workflow, combined with redirection on OAuth errors to capture access tokens. The attack works roughly like this:
- Create an OAuth application on Phabricator.
- Set the domain to `evil.com`.
- Grab the OAuth URI for it (something like `https://phabricator.com/oauthserver/auth/?redirect_uri=http://evil.com&...`).
- Add an invalid `scope` parameter (`scope=xyz`).
- Use //that// URI to build a Facebook OAuth URI (something like `https://facebook.com/oauth/?redirect_uri=http://phabricator.com/...&response_type=token`).
- After the user authorizes the application on Facebook (or instantly if they've already authorized it), they're redirected to the OAuth server, which processes the request. Since this is the 'token' workflow, it has auth information in the URL anchor/fragment.
- The OAuth server notices the `scope` error and 302's to the attacker's domain, preserving the anchor in most browsers through anchor reattachment.
- The attacker reads the anchor in JS and can do client workflow stuff.
To fix this, I've made several general changes/modernizations:
- Add a new application and make it beta. This is mostly cleanup, but also turns the server off for typical installs (it's not generally useful quite yet).
- Add a "Console" page to make it easier to navigate.
- Modernize some of the UI, since I was touching most of it anyways.
Then I've made specific security-focused changes:
- In the web-based OAuth workflow, send back a human-readable page when errors occur. I //think// this is universally correct. Previously, humans would get a blob of JSON if they entered an invalid URI, etc. This type of response is correct for the companion endpoint ("ServerTokenController") since it's called by programs, but I believe not correct for this endpoint ("AuthController") since it's used by humans. Most of this is general cleanup (give humans human-readable errors instead of JSON blobs).
- Never 302 off this endpoint automatically. Previously, a small set of errors (notably, bad `scope`) would cause a 302 with 'error'. This exposes us to anchor reattachment, and isn't generally helpful to anyone, since the requesting application did something wrong and even if it's prepared to handle the error, it can't really do anything better than we can.
- The only time we'll 'error' back now from this workflow is if a user explicitly cancels the workflow. This isn't a 302, but a normal link (the cancel button), so the anchor is lost.
- Even if the application is already approved, don't blindly 302. Instead, show the user a confirmation dialog with a 'continue' link. This is perhaps slightly less user-friendly than the straight redirect, but I think it's pretty reasonable in general, and it gives us a lot of protection against these classes of attack. This redirect is then through a link, not a 302, so the anchor is again detached.
-
Test Plan: I attempted to hit everything I touched. See screenshots.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: aran, epriestley
Maniphest Tasks: T4593
Differential Revision: https://secure.phabricator.com/D8517
2014-03-13 20:59:10 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
final class PhabricatorApplicationOAuthServer extends PhabricatorApplication {
|
|
|
|
|
|
|
|
public function getBaseURI() {
|
|
|
|
return '/oauthserver/';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getShortDescription() {
|
|
|
|
return pht('OAuth Provider');
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getIconName() {
|
|
|
|
return 'oauthserver';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getTitleGlyph() {
|
2014-03-14 16:46:07 +01:00
|
|
|
return "\xE2\x99\x86";
|
Fix an anchor redirect issue with OAuth server, plus modernize the application a bit
Summary:
Ref T4593. Via HackerOne. An attacker can use the anchor reattachment, combined with the Facebook token workflow, combined with redirection on OAuth errors to capture access tokens. The attack works roughly like this:
- Create an OAuth application on Phabricator.
- Set the domain to `evil.com`.
- Grab the OAuth URI for it (something like `https://phabricator.com/oauthserver/auth/?redirect_uri=http://evil.com&...`).
- Add an invalid `scope` parameter (`scope=xyz`).
- Use //that// URI to build a Facebook OAuth URI (something like `https://facebook.com/oauth/?redirect_uri=http://phabricator.com/...&response_type=token`).
- After the user authorizes the application on Facebook (or instantly if they've already authorized it), they're redirected to the OAuth server, which processes the request. Since this is the 'token' workflow, it has auth information in the URL anchor/fragment.
- The OAuth server notices the `scope` error and 302's to the attacker's domain, preserving the anchor in most browsers through anchor reattachment.
- The attacker reads the anchor in JS and can do client workflow stuff.
To fix this, I've made several general changes/modernizations:
- Add a new application and make it beta. This is mostly cleanup, but also turns the server off for typical installs (it's not generally useful quite yet).
- Add a "Console" page to make it easier to navigate.
- Modernize some of the UI, since I was touching most of it anyways.
Then I've made specific security-focused changes:
- In the web-based OAuth workflow, send back a human-readable page when errors occur. I //think// this is universally correct. Previously, humans would get a blob of JSON if they entered an invalid URI, etc. This type of response is correct for the companion endpoint ("ServerTokenController") since it's called by programs, but I believe not correct for this endpoint ("AuthController") since it's used by humans. Most of this is general cleanup (give humans human-readable errors instead of JSON blobs).
- Never 302 off this endpoint automatically. Previously, a small set of errors (notably, bad `scope`) would cause a 302 with 'error'. This exposes us to anchor reattachment, and isn't generally helpful to anyone, since the requesting application did something wrong and even if it's prepared to handle the error, it can't really do anything better than we can.
- The only time we'll 'error' back now from this workflow is if a user explicitly cancels the workflow. This isn't a 302, but a normal link (the cancel button), so the anchor is lost.
- Even if the application is already approved, don't blindly 302. Instead, show the user a confirmation dialog with a 'continue' link. This is perhaps slightly less user-friendly than the straight redirect, but I think it's pretty reasonable in general, and it gives us a lot of protection against these classes of attack. This redirect is then through a link, not a 302, so the anchor is again detached.
-
Test Plan: I attempted to hit everything I touched. See screenshots.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: aran, epriestley
Maniphest Tasks: T4593
Differential Revision: https://secure.phabricator.com/D8517
2014-03-13 20:59:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getFlavorText() {
|
2014-03-14 16:46:07 +01:00
|
|
|
return pht('Login with Phabricator');
|
Fix an anchor redirect issue with OAuth server, plus modernize the application a bit
Summary:
Ref T4593. Via HackerOne. An attacker can use the anchor reattachment, combined with the Facebook token workflow, combined with redirection on OAuth errors to capture access tokens. The attack works roughly like this:
- Create an OAuth application on Phabricator.
- Set the domain to `evil.com`.
- Grab the OAuth URI for it (something like `https://phabricator.com/oauthserver/auth/?redirect_uri=http://evil.com&...`).
- Add an invalid `scope` parameter (`scope=xyz`).
- Use //that// URI to build a Facebook OAuth URI (something like `https://facebook.com/oauth/?redirect_uri=http://phabricator.com/...&response_type=token`).
- After the user authorizes the application on Facebook (or instantly if they've already authorized it), they're redirected to the OAuth server, which processes the request. Since this is the 'token' workflow, it has auth information in the URL anchor/fragment.
- The OAuth server notices the `scope` error and 302's to the attacker's domain, preserving the anchor in most browsers through anchor reattachment.
- The attacker reads the anchor in JS and can do client workflow stuff.
To fix this, I've made several general changes/modernizations:
- Add a new application and make it beta. This is mostly cleanup, but also turns the server off for typical installs (it's not generally useful quite yet).
- Add a "Console" page to make it easier to navigate.
- Modernize some of the UI, since I was touching most of it anyways.
Then I've made specific security-focused changes:
- In the web-based OAuth workflow, send back a human-readable page when errors occur. I //think// this is universally correct. Previously, humans would get a blob of JSON if they entered an invalid URI, etc. This type of response is correct for the companion endpoint ("ServerTokenController") since it's called by programs, but I believe not correct for this endpoint ("AuthController") since it's used by humans. Most of this is general cleanup (give humans human-readable errors instead of JSON blobs).
- Never 302 off this endpoint automatically. Previously, a small set of errors (notably, bad `scope`) would cause a 302 with 'error'. This exposes us to anchor reattachment, and isn't generally helpful to anyone, since the requesting application did something wrong and even if it's prepared to handle the error, it can't really do anything better than we can.
- The only time we'll 'error' back now from this workflow is if a user explicitly cancels the workflow. This isn't a 302, but a normal link (the cancel button), so the anchor is lost.
- Even if the application is already approved, don't blindly 302. Instead, show the user a confirmation dialog with a 'continue' link. This is perhaps slightly less user-friendly than the straight redirect, but I think it's pretty reasonable in general, and it gives us a lot of protection against these classes of attack. This redirect is then through a link, not a 302, so the anchor is again detached.
-
Test Plan: I attempted to hit everything I touched. See screenshots.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: aran, epriestley
Maniphest Tasks: T4593
Differential Revision: https://secure.phabricator.com/D8517
2014-03-13 20:59:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getApplicationGroup() {
|
|
|
|
return self::GROUP_UTILITIES;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function isBeta() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getRoutes() {
|
|
|
|
return array(
|
|
|
|
'/oauthserver/' => array(
|
|
|
|
'' => 'PhabricatorOAuthServerConsoleController',
|
|
|
|
'auth/' => 'PhabricatorOAuthServerAuthController',
|
|
|
|
'test/' => 'PhabricatorOAuthServerTestController',
|
|
|
|
'token/' => 'PhabricatorOAuthServerTokenController',
|
|
|
|
'client/' => array(
|
|
|
|
'' => 'PhabricatorOAuthClientListController',
|
|
|
|
'create/' => 'PhabricatorOAuthClientEditController',
|
|
|
|
'delete/(?P<phid>[^/]+)/' => 'PhabricatorOAuthClientDeleteController',
|
|
|
|
'edit/(?P<phid>[^/]+)/' => 'PhabricatorOAuthClientEditController',
|
|
|
|
'view/(?P<phid>[^/]+)/' => 'PhabricatorOAuthClientViewController',
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-03-18 21:30:48 +01:00
|
|
|
protected function getCustomCapabilities() {
|
|
|
|
return array(
|
|
|
|
PhabricatorOAuthServerCapabilityCreateClients::CAPABILITY => array(
|
|
|
|
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
Fix an anchor redirect issue with OAuth server, plus modernize the application a bit
Summary:
Ref T4593. Via HackerOne. An attacker can use the anchor reattachment, combined with the Facebook token workflow, combined with redirection on OAuth errors to capture access tokens. The attack works roughly like this:
- Create an OAuth application on Phabricator.
- Set the domain to `evil.com`.
- Grab the OAuth URI for it (something like `https://phabricator.com/oauthserver/auth/?redirect_uri=http://evil.com&...`).
- Add an invalid `scope` parameter (`scope=xyz`).
- Use //that// URI to build a Facebook OAuth URI (something like `https://facebook.com/oauth/?redirect_uri=http://phabricator.com/...&response_type=token`).
- After the user authorizes the application on Facebook (or instantly if they've already authorized it), they're redirected to the OAuth server, which processes the request. Since this is the 'token' workflow, it has auth information in the URL anchor/fragment.
- The OAuth server notices the `scope` error and 302's to the attacker's domain, preserving the anchor in most browsers through anchor reattachment.
- The attacker reads the anchor in JS and can do client workflow stuff.
To fix this, I've made several general changes/modernizations:
- Add a new application and make it beta. This is mostly cleanup, but also turns the server off for typical installs (it's not generally useful quite yet).
- Add a "Console" page to make it easier to navigate.
- Modernize some of the UI, since I was touching most of it anyways.
Then I've made specific security-focused changes:
- In the web-based OAuth workflow, send back a human-readable page when errors occur. I //think// this is universally correct. Previously, humans would get a blob of JSON if they entered an invalid URI, etc. This type of response is correct for the companion endpoint ("ServerTokenController") since it's called by programs, but I believe not correct for this endpoint ("AuthController") since it's used by humans. Most of this is general cleanup (give humans human-readable errors instead of JSON blobs).
- Never 302 off this endpoint automatically. Previously, a small set of errors (notably, bad `scope`) would cause a 302 with 'error'. This exposes us to anchor reattachment, and isn't generally helpful to anyone, since the requesting application did something wrong and even if it's prepared to handle the error, it can't really do anything better than we can.
- The only time we'll 'error' back now from this workflow is if a user explicitly cancels the workflow. This isn't a 302, but a normal link (the cancel button), so the anchor is lost.
- Even if the application is already approved, don't blindly 302. Instead, show the user a confirmation dialog with a 'continue' link. This is perhaps slightly less user-friendly than the straight redirect, but I think it's pretty reasonable in general, and it gives us a lot of protection against these classes of attack. This redirect is then through a link, not a 302, so the anchor is again detached.
-
Test Plan: I attempted to hit everything I touched. See screenshots.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: aran, epriestley
Maniphest Tasks: T4593
Differential Revision: https://secure.phabricator.com/D8517
2014-03-13 20:59:10 +01:00
|
|
|
}
|