Headlines are flying around this morning that a “serious security flaw” (now dubbed “Covert Redirect”) has been discovered in OAuth and OpenID, which could be exploited by malicious sites to capture user’s personal data. Furthermore, the “reporting” includes comments from major auth providers (Google, Microsoft, Facebook) to the effect of “we can’t fix this”.
This is not a vulnerability of OAuth itself. The exploit requires the use of an open redirect on your client web site. If you have a URL on your web site that blindly redirects the browser to whatever URL is encoded in the parameters AND you forward URL query params to the redirected page as well, then you have a massive security hole in your web site that can be exploited to capture user personal data and control of the user’s account on your site. This open redirect exploit is not specific to OAuth; an open redirect can be leveraged to exploit a wide variety of services. Open redirects have been well known as a Very Bad Idea for decades.
- Don’t expose an open redirect on your web server (duh!)
- Or if you do expose a redirect endpoint, restrict the destination URL to your own domain(s).
- If you must redirect to arbitrary 3rd party domains (really? why?), at least strip away the query params.
Passive federated authentication usually involves a web site (example.com) making a login request to an authentication site (google,com, facebook.com, etc). The auth site prompts the user to log in to the auth provider’s domain (google.com, etc), and then issues an auth code or access token to the original web site (example.com). This auth code is passed from the auth provider to the original web site by redirecting the browser to a url on the original web site. The auth code is usually passed as a parameter in the URL query of the redirect.
Most auth providers will only redirect to a URL with a domain name that is preset in the client web site’s configuration data with that provider. This is to prevent the auth provider from being used as an open redirect. Google, Microsoft, etc, do the right thing.
Note: Facebook supports redirect URL whitelisting in their app configuration, but Facebook does not require that it be set. If your client app uses the Facebook default settings, your users who use Facebook to login to your app are vulnerable to redirect attacks and information theft. Set the OAuth redirect URL in the Facebook settings to close this security hole.
(for clarity, URLs in query params in the examples below are not URL encoded)
- Your web site example.com requests the user login from auth provider, and includes in the request a callback URL to receive auth code: https://example.com/receiveAuthCode
- Auth provider authenticates user
- Auth provider validates that the given callback URL (example.com/receiveAuthCode) matches the auth provider’s provisioning data for example.com.
- Auth provider redirects to https://example.com/receiveAuthCode and attaches the auth code as a query param: https://example.com/receiveAuthCode/?&code=asdfewreaf12321
- Example.com/receiveAuthCode responds by capturing the auth code query param, converting the auth code into an access token in another request to the auth provider, and stores the access token in a browser session cookie so that it can be used across multiple web pages on example.com
- User visits example.com/myprofile
- Example.com realizes user is not authenticated, redirects to auth provider login and includes the URL of the original page requested by the user in the receive auth code redirect: https://example.com/redirect/?&original_page=https://example.com/myprofile
- Auth provider does authentication, validates the domain of redirect against provisioned configuration, and redirects to the given redirect url
- Example.com/redirect further redirects to https://example.com/myprofile AND copies the query parameters to the redirected URL: https://example.com/myprofile/&code=asdfasdfasd3456
- example.com/myprofile sees the auth code on the URL and performs steps to convert it to an access token, fetch the user’s personal data, and display the profile page.
- Evil.com discovers that example.com implements a redirect endpoint (example.com/redirect)
- Evil.com constructs a new url from scratch to request authentication from an auth provider (google.com), replacing the example.com/myprofile portion of the authredirect url with evil.com/gotcha: authredirect=https://example.com/redirect/?&original_page=http://evil.com/gotcha
- Evil.com manages to get the user to click on a link which navigates to the auth provider with that doctored redirect url
- User logs in seeing “example.com” as the referring app.
- Auth provider does authentication, validates domain of redirect against provisioned configuration, and redirects to given redirect url, with auth code parameter attached: http://example.com/redirect?&original_page=https://evil.com/gotcha&code=sdfgsfdgqwr542
- Example.com/redirect redirects the browser to https://evil.com/gotcha AND copies the query parameters to the redirected URL: https://evil.com/gotcha/?&code=sdfgsfdgqwr542
- Evil.com can now redeem that code for an access token and use that access token to access user data from the auth provider (google.com) as well as potentially full access to user account on example.com (if example.com exposes an API secured by the same access token)
It’s not difficult to thwart this open redirect exploit:
- Make sure you specify an OAuth redirect URI in the app configuration settings with every OAuth provider your app uses.
- Don’t implement redirect URLs on your web site.
- If redirects are required for your web site workflow, restrict the redirect endpoint to only redirecting to URLs within your own site. Do not copy the query params to the redirected URL. Perform the processing of auth code to access token on the redirect endpoint and store the access token in a browser session cookie before redirecting to the page the user originally request.
There are legitimate reasons to implement a limited redirect endpoint on your web site. The most common use case: after the login process is complete, redirect the browser to the web page (on your site) that the user originally requested. This use of redirects should be constrained to only perform the redirect if the requested destination URL is in your site’s domain.