Git Product home page Git Product logo

Comments (30)

jamesridgway avatar jamesridgway commented on August 21, 2024 45

I've consolidates some of the pieces of advice in the various comments into the following step by step guide with a sample project:
https://www.jamesridgway.co.uk/implementing-a-two-step-otp-u2f-login-workflow-with-rails-and-devise/

from devise-two-factor.

dzaporozhets avatar dzaporozhets commented on August 21, 2024 10

I think this requires at least small section in README. Since every service implements 2FA in 2 steps - its really unclear how to implement it with current library.

from devise-two-factor.

bsedat avatar bsedat commented on August 21, 2024 7

GitLab uses devise-two-factor with a two-step login. I believe the login is in their SessionsController and this concern. I believe they store the user ID in the signed/encrypted Rails session.

I'd definitely welcome any clarifications to the README about this from someone who has implemented it. I believe GitLab's method addresses @borski's security concerns above.

from devise-two-factor.

jeffreyyong avatar jeffreyyong commented on August 21, 2024 5

@rikkipitt Sorry for the late reply. Unfortunately, I can't post my implementation to you because it's my company code that is not open source. However, I referred to the Gitlab open source code: Gitlab The two main files that I looked at were app/controllers/sessions_controller.rb and app/controllers/concerns/authenticates_with_two_factor.rb

from devise-two-factor.

jonathansimmons avatar jonathansimmons commented on August 21, 2024 3

Updating my comment. I've ending up using https://github.com/wmlele/devise-otp and have spent a good amount of time activley contributing to it.

The gem resolved this flow and has a lot of flexibility. Again just an FYI for those looking for this feature inparticular.

from devise-two-factor.

connorshea avatar connorshea commented on August 21, 2024 3

We run a bug bounty program so our implementation should be pretty secure :)

from devise-two-factor.

rikkipitt avatar rikkipitt commented on August 21, 2024 1

@jeffreyyong Would you be kind enough to demonstrate your implementation please? When you get the time of course!

from devise-two-factor.

jeffreyyong avatar jeffreyyong commented on August 21, 2024 1

@connorshea Yes! Open source rocks! :)

from devise-two-factor.

ziaulrehman40 avatar ziaulrehman40 commented on August 21, 2024 1

Got mine working too with help of GitLab's implementation.

from devise-two-factor.

QuinnWilton avatar QuinnWilton commented on August 21, 2024

Sorry about the late reply!

I don't have any code examples of this, but I know of at least two websites who've managed to turn the flow from this gem into a two-step process.

They used the session to keep track of what stage the user is at in the login, and used a before_filter to redirect to the correct login page based on the stage. Unfortunately I'm a bit busy dealing with POODLE right now, so I can't put together an example, but if you have any questions I'd be happy to see what I can do to help.

from devise-two-factor.

jonathansimmons avatar jonathansimmons commented on August 21, 2024

I found a way to do this but am not 100% sure about it as it requires some form of user identification is passed to the second step form.

  • User logs in
  • A before filter fires on Session create
    • Finds the user based on e-mail provided
    • Validates the email and password
    • Redirects to Two-Factor step two if two factor enabled
  • Two-Factor step two is a second form requesting ota_attempt
    • A UID is stored in a hidden field on the form
    • User submits ota_attemptand we validate to stored user

Maybe this is acceptable, We confirm user pass in step one and confirm the ota_attemp to the stored user in step two. It just feels clunky. I feel like I should be able to make this work without having to pass user data in forms or session variables. Any advice?

from devise-two-factor.

jessicard avatar jessicard commented on August 21, 2024

@jonathansimmons Thanks for opening this issue - I'm attempting to do this as well. Would also love an example.

from devise-two-factor.

loopj avatar loopj commented on August 21, 2024

👍 any ideas?

from devise-two-factor.

QuinnWilton avatar QuinnWilton commented on August 21, 2024

@jonathansimmons Sorry about the late reply!

I think your approach is more or less correct. I agree that passing user data to the form is a little clunky, so I think sessions are the way to go. Given that Rails handles session signing for you, you won't have to worry about session tampering at this stage.

I think as long as you make sure the incomplete session expires within a reasonable amount of time, you should be good as far as security is concerned.

Unfortunately I can't see a nicer way of handling it than what you have already.

from devise-two-factor.

jonathansimmons avatar jonathansimmons commented on August 21, 2024

I'm closing this as I don't feel it's really @ShaneWilton's problem.

I went ahead and forked this repo, created an examples dir, moved the existing demo into /one-step and put my current (kinda ghetto) two-step example in /two-step

@ShaneWilton any input /improvements are welcomed...
https://github.com/jonathansimmons/devise-two-factor

from devise-two-factor.

ajb avatar ajb commented on August 21, 2024

Howdy folks, late to the discussion, but wondering if this might work: (modified from @jonathansimmons)

  • User logs in
  • A before filter fires on Session create
    • Finds the user based on e-mail provided
    • Validates the email and password
    • renders the Two-Factor step two if two factor enabled
  • Two-Factor step two is a second form requesting ota_attempt
    • hidden fields store the plaintext email/password/remember_me
    • User submits ota_attempt and we validate to stored user

Initially this seemed insecure, but how insecure is it really? The only vulnerability I can think of is if the user walks away from the computer while their browser is on the two-factor page, and a potential attacker comes and inspects the DOM for their plaintext password.... and this isn't really a vulnerability, right?

What am I missing? ;)

from devise-two-factor.

borski avatar borski commented on August 21, 2024

Although it seems innocent, putting a plaintext password on a page is a really really bad idea. There are a ton of reasons:

  1. Someone walking away from their computer is absolutely a vulnerability. It's the same reason it's important to disable autocomplete for password fields - people at an internet cafe or library will be vulnerable to this.
  2. Pages get cached. A page that gets cached in a browser on a public computer that includes your plaintext password is bad news.
  3. Pages get saved by accident. All it takes is one accidental hit of Ctrl-S and there's a page on the desktop for anyone to open up later and get the plaintext password.
  4. ...

You kind of get where this is going - including the plaintext password on a page is a really bad idea due to the myriad number of ways in which an attacker can later access it; even if they don't have local access to the computer, but they have a RAT set up, they can later look at the cache and pull down their password.

The best way to do this, I think, is to pass some sort of secure signature along that you can verify, server-side, as having been a user authenticated via password. That way you don't have to pass along a uid or anything like that either. Ideally, you'd want to time-bound and expire the signature somehow as well.

Additionally, rails sessions are conveniently signed already, so you could simply add a parameter to the session as well, but you may need to clean it up after they're logged in or if they choose not to complete the login process.

Does that make sense?

from devise-two-factor.

ajb avatar ajb commented on August 21, 2024

Yup, thanks for the sanity check. Pushing a fix to our integration right now.

from devise-two-factor.

rikkipitt avatar rikkipitt commented on August 21, 2024

Hey @jonathansimmons, I just stumbled upon this thread as I'm looking at creating a two-stage login using this gem and your fork is dead. Did you manage to get this working nicely with tinfoil/devise-two-factor before I jump in and try it myself? It would be good to hear what troubles you encountered before I tackle it myself if you've got a moment to comment.

Cheers,
Rikki

from devise-two-factor.

jonathansimmons avatar jonathansimmons commented on August 21, 2024

@rikkipitt The last time I used my fork it was working fine. Devise has been updated a few times since then.

I did make some significant customizations in my exact implementation. I needed it for a project a littler over a year ago. I tried to make some progress with the maintainer but he stopped communicating.

That being said it's lightweight and should work. Email me if you have questions and I'll see if I can help.

from devise-two-factor.

rikkipitt avatar rikkipitt commented on August 21, 2024

Cheers @jonathansimmons. What I've got so far is a normal login with a before_filter to check if the user has otp_required_for_login set to true - redirects to a verification form view. I'm storing the email/password in session (encrypted).

The problem I'm now having is merging the email/password params and the verification code before triggering the default sessions_controller create method. How did you do the auth step in the end?

Cheers

from devise-two-factor.

jonathansimmons avatar jonathansimmons commented on August 21, 2024

@rikkipitt email me at jon{at}jsdev.co so we can move it off this thread as it's not relevant to this repo.

from devise-two-factor.

jeffreyyong avatar jeffreyyong commented on August 21, 2024

Hi @jonathansimmons, I am wondering if the gem that you suggested: https://github.com/wmlele/devise-otp is building on top of tinfoil/devise-two-factor, or is it a solo gem by itself?

I have implemented all the backup codes and the verification code with tinfoil/devise-two-factor and I am wondering if I can combine the implementation with the gem that you suggested. I am currently stuck at the two-step log-in feature.

from devise-two-factor.

jeffreyyong avatar jeffreyyong commented on August 21, 2024

Hey, I am wondering if anyone managed to implement the second login step using tinfoil/devise-two-factor gem? I have implemented a bulk of the features using this gem, and the only thing that is lacking is the second login step.

from devise-two-factor.

jeffreyyong avatar jeffreyyong commented on August 21, 2024

@bsedat Thanks for letting me know that big project like Gitlab is using tinfoil/devise-two-factor as well. I will try to tinker with it and see if it works for my project.

from devise-two-factor.

jonathansimmons avatar jonathansimmons commented on August 21, 2024

@jeffreyyong no it does not build upon this gem. I believe it was based off a google authenticator gem.

It's been a while since I've used either of these gems personally but I know each of them can do what you're looking for with a little elbow grease.

from devise-two-factor.

jeffreyyong avatar jeffreyyong commented on August 21, 2024

@connorshea I managed to implement the two-step login in my system after looking at the GitLab example! Thank you very much.

from devise-two-factor.

connorshea avatar connorshea commented on August 21, 2024

@jeffreyyong that's really great to hear! Open source at work <3

from devise-two-factor.

asia653 avatar asia653 commented on August 21, 2024

A few of you have suggested using the session cookiestore to store the state of the user

I would recommend storing it in a custom cookie (specifically an encrypted one) so that you can set a separate expiry time (5 minutes) instead of using a rails session cookie (where setting a short expiry can be very inconvenient)

from devise-two-factor.

evgenyneu avatar evgenyneu commented on August 21, 2024

A security improvement idea. In addition to storing user's id in the session (to load the user on 2FA screen)

session[:otp_user_id] = user.id

I suggest storing a random token

session[:otp_user_token] = SecureRandom.alphanumeric(64)

Next, compute a bcrypt hash and its expiration time and store these in the users table. On 2FA screen, load the user by its :otp_user_id, check if the :otp_user_token token corresponds to the hash and check the token's expiration date. This gives additional security if you store your session in an encrypted cookie. It remains secure even if cookie encryption key leaks out. It also allows to invalidate the token on the server side.

from devise-two-factor.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.