Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

High Risk Vulnerability in Parent OmniAuth Library #82

Closed
joshcanhelp opened this issue Jul 18, 2019 · 11 comments
Closed

High Risk Vulnerability in Parent OmniAuth Library #82

joshcanhelp opened this issue Jul 18, 2019 · 11 comments
Assignees
Labels

Comments

@joshcanhelp
Copy link
Contributor

joshcanhelp commented Jul 18, 2019

We are aware of a vulnerability in the parent OmniAuth library that this strategy relies on. This was reported over 4 years ago in this PR but no fix has been released yet. It just recently came to our attention (and others) when our dependency scanner started pinging us about CVE-2015-9284.

In summary, the vulnerability allows an attacker to link an external identity provider to a user signed into the application using OmniAuth if certain conditions apply. This request forgery requires having 2 or more allowed identity sources for the application and can affect both Ruby-only and Rails-enabled applications. Even if you are only using the Auth0 strategy, specific providers can be indicated in a connection parameter on the auth URL like so:

https://yourapp.com/auth/auth0?connection=google-oauth2

This will limit the authentication request to a single connection, in this example case the Google social connection, and return to the application with a valid ID token. Default behavior for an application using our quickstart is to log the user in with this new ID token. If your application does any kind of account linking then this could create a situation where an attacker's Google account could be associated with the user account for the application by just visiting a URL. Again, this would require no-action account linking to be implemented in your application and the user to be logged into an attacker's account on an external identity provider used by the application.

The OmniAuth community has since published a mitigation draft document that walks through how to secure an app with this vulnerability in place, both for Ruby and Rails-enabled applications. The main mitigation presented there is to POST to the auth URL so a CSRF token can be used and direct links could not start the auth process. Other considerations:

  • Issue a warning before redirecting logged-in users that they are about to start a new auth session.
  • Display a clear message before linking accounts, like "Are you sure you want to link your account for [email protected] with [email protected]?"

In the meantime, we have one of two options for this library:

  1. Wait for the parent library to address the issue. While the issue has been around for several years, there has been a lot of recent discussion. This will hopefully lead to a fix (even if it requires a major release).
  2. Switch this library to be Rails-only and switch to omniauth-rails once this PR is merged.

Taking route 1 would mean that we're waiting for an indeterminate time before this is fixed (which is fine if mitigations can be put in place but there's no way to contact everyone using this library). Taking route 2 means that Ruby-only applications do not have a good authentication solution (the Ruby SDK has the endpoints needed but does not handle callbacks, session, state, etc).

We appreciate any feedback that you have. In the meantime, we'll be weighing the two options above, looking for additional ways to address this, and answering any questions you might have. We'll leave this open until a fix is in place, one way or another.

@joshcanhelp joshcanhelp pinned this issue Jul 18, 2019
@jkhulme
Copy link

jkhulme commented Jul 22, 2019

Hi @joshcanhelp thanks for the update. Its been frustrating seeing the slow progress in omniauth

We only have rails apps using auth0, so switching to omniauth-rails wouldn't be a problem for us. But I think it would be good if we could get a fix for everyone.

For mitigiations - "POST to the auth URL so a CSRF token can be used and direct links could not start the auth process" is that posting to /auth/auth0 or auth0/callback or something else entirely?

@forrestblount
Copy link

I would vote for the rails based option as a supported branch of this library at minimum while we wait for the long term fix in omniauth.

@joshcanhelp
Copy link
Contributor Author

@jkhulme - Happy to help and thanks for your response. For that mitigation, the POST would be to the /auth/auth0 URL with a CSRF token. That would ensure that requests to that URL only come from your site and not from somewhere else (malicious site/email).

@forrestblount - Thanks for your response. We're working on updates to our documentation (README in this repo and the Quickstart) and we'll consider a supported branch for Rails.

@joshcanhelp
Copy link
Contributor Author

Update here ... I'm testing out the mitigation options and can confirm that the cookpad/omniauth-rails_csrf_protection gem works as expected and blocks external requests to the auth URL. Just following the instructions on the README, I added:

# Gemfile
gem 'omniauth-auth0' # Already there
gem 'omniauth-rails_csrf_protection'

... and this everywhere there were login links:

<% if logged_in? %>
  <%= link_to 'Logout', 'auth/logout', method: :post %>
<% else %>
  <%= link_to 'Login', 'auth/auth0', method: :post %>
<% end %>

Login works as expected and directly accessing the auth/auth0 URL ends with No route matches [GET] "/auth/auth0".

We'll work on getting this added to the samples and quickstarts for Rails, as well as guidance for Ruby-only applications using this gem.

@joshcanhelp
Copy link
Contributor Author

Finished setting up and testing a Rack application using the mitigation linked above and all worked as expected. Sample app is here:

https://github.com/joshcanhelp/omniauth-auth0-ruby

Working on adding these to samples and quickstarts now 👍

@stale stale bot added the closed:stale Issue or PR has not seen activity recently label Nov 3, 2019
@auth0 auth0 deleted a comment from stale bot Nov 4, 2019
@stale stale bot removed the closed:stale Issue or PR has not seen activity recently label Nov 4, 2019
@joshcanhelp joshcanhelp self-assigned this Nov 4, 2019
@tjbarber
Copy link

tjbarber commented Feb 3, 2020

Hey Josh,

I'm trying to implement Auth0 in a few apps and would still like to be able to redirect to a login page instead of a home page with a login button. Is there a workaround that would allow this?

Thanks for your help!

@szTheory
Copy link

Is there a way to redirect directly to the Auth0 login page since you can't redirect with POST, and GET has been taken away? The current recommended workflow is a poor user experience for new user invitations. They have to click an email link to activate their account, then set their password on an Auth0 form, then get redirected to the application website where they have to click another button to be redirected to another Auth0 form, where they have to fill in their credentials yet again and click login again.

Would hope for something better from a paid product. It's been a challenge setting up user invitation by overriding the Auth0 password reset email with custom JavaScript since the Auth0 docs don't give code examples or screenshots, the instructions themselves are not clear, and invitation is not supported out of the box. So after finally getting that all set up, it's disappointing to see the backend still has issues. As it stands I wouldn't want to use Auth0 on another project.

In case anyone is stuck on the JavaScript, here's what I came up with. You add #invite to the end of the change password ticket URL you get back from the API after creating one. Then put this custom JavaScript into the password reset email so you can conditionally set the language shown on the Auth0 password reset form.

    var hash = window.location.hash.substr(1);
    var invite = hash.includes("invite");
    var headerText = invite ? "Set your password for <br />{email}" : "Enter a new password for<br />{email}";
    var title = invite ? "New account setup" : "Change Password";
    var passwordPlaceholder = invite ? "your password" : "your new password";
    var passwordConfirmationPlaceholder = invite ? "confirm your password" : "confirm your new password";
    var successMessage = invite ? "Account set up successfully" : "Your password has been reset successfully.";

    new Auth0ChangePassword({
      container:         "change-password-widget-container",                // required
      email:             "{{email | escape}}",                              // DO NOT CHANGE THIS
      csrf_token:        "{{csrf_token}}",                                  // DO NOT CHANGE THIS
      ticket:            "{{ticket}}",                                      // DO NOT CHANGE THIS
      password_policy:   "{{password_policy}}",                             // DO NOT CHANGE THIS
      password_complexity_options:  {{password_complexity_options}},        // DO NOT CHANGE THIS
      theme: {
        icon: "{{tenant.picture_url | default: '//cdn.auth0.com/styleguide/1.0.0/img/badge.png'}}",
        primaryColor: "{{tenant.colors.primary | default: '#ea5323'}}"
      },
      dict: {
        passwordPlaceholder: passwordPlaceholder,
        passwordConfirmationPlaceholder: passwordConfirmationPlaceholder,
        // passwordConfirmationMatchError: "Please ensure the password and the confirmation are the same.",
        // passwordStrength: {
        //   containsAtLeast: "Contain at least %d of the following %d types of characters:",
        //   identicalChars: "No more than %d identical characters in a row (e.g., "%s" not allowed)",
        //   nonEmpty: "Non-empty password required",
        //   numbers: "Numbers (i.e. 0-9)",
        //   lengthAtLeast: "At least %d characters in length",
        //   lowerCase: "Lower case letters (a-z)",
        //   shouldContain: "Should contain:",
        //   specialCharacters: "Special characters (e.g. !@#$%^&*)",
        //   upperCase: "Upper case letters (A-Z)"
        // },
        successMessage: successMessage,
        // configurationError: "An error ocurred. There appears to be a misconfiguration in the form.",
        // networkError: "The server cannot be reached, there is a problem with the network.",
        // timeoutError: "The server cannot be reached, please try again.",
        // serverError: "There was an error processing the password reset.",
        headerText: headerText,
        title: title,
        // weakPasswordError: "Password is too weak."
        // passwordHistoryError: "Password has previously been used."
      }
    });

@scottsherwood
Copy link

@joshcanhelp I've been referred here from one of your auth0 support colleagues.

With a new version of the parent omniauth library being released that resolves this vulnerability. Is there any plans for auth0 to provide an update to make use of omniauth v2 here?

@joshcanhelp
Copy link
Contributor Author

cc @davidpatrick

@davidpatrick
Copy link
Contributor

Hey @scottsherwood to give some context, the new release that resolves the vulnerability is a similar solution that @joshcanhelp has laid out in this issue and on our sample/quickstart. It is also the same end result as the mitigation plan from https://github.com/omniauth/omniauth/wiki/Resolving-CVE-2015-9284.

The new version defaults to only POST as the allowed request_phase method. Which you were hopefully already doing as detailed in the CVE mitigation.

We are currently reviewing the Omniauth v2 release, and will be planning an upgrade for it. Thanks.

@davidpatrick
Copy link
Contributor

Addressed in #128

@davidpatrick davidpatrick unpinned this issue May 10, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants