Implementing a secure two-factor authentication for a login page with Django form wizard

8.3k views Asked by At

So basically i want to achieve something similar to Google Two-factor authentication implementation. My login form consists of a 2-step form wizard:

  1. Step 1 (verifying username and password)
  2. Step 2 (authenticate security token)

The usage scenarios would be:

  1. User has a security token associated with his account: logs user in if user passes Step 1 and Step 2
  2. User doesn't have a security token: logs user in right after he passes Step 1 only

I'm subclassing django's Form Wizard now to be used as my login view. In Step 2, by default Django FormWizard will include field values from previously submitted forms as hidden fields. But as you know, password is entered in Step 1, so I don't want to include it in Step 2 for security reasons.

My first thought would be to use session to indicate if a user has passed Step 1, so I don't need to include field values from Step 1.. but I may be overlooking something here. What are the more secure solutions to this?

Also I don't quite understand the use of security-hash in FormWizard. Can someone explain?

Thanks a lot.

5

There are 5 answers

3
Filip Dupanović On BEST ANSWER

I'm not exactly getting the point of the security token, but it would seem simpler and faster if you forgo extending the FormWizard and just implement it as two separate views. The whole point of the FormWizard is to break and aggregate several forms into one and your particular use case goes against it—you'd just be hacking it to functionally do something otherwise.

As for the security hash, it calculates a hash for all of the form data from successfully completed steps. This is just a security measure to ensure that the form data has not changed/been tampered with inbetween steps and that none of the steps were otherwise bypassed somehow.

1
Karl Anderson On

Duo Security's duo_web project has an open source Django demo which will show you one way to do this (I am a Duo developer).

The demo setup has a @duo_auth_requried decorator similar to the builtin @login_required which checks for a session cookie indicating that the user has passed the 2nd factor authentication. The @login_required decorator verifies local authentication, the @duo_auth_required decorator verifies 2nd factor authentication, and the lack of either redirects the user to the relevant form.

The difference with your description is that we don't authenticate both in a single form or pass credentials between forms, we do them separately. Just protect a view with both decorators and you can rely on Django to assert local authentication before the 2nd factor auth is attempted.

0
psagers On

The django-otp project adds pluggable two-factor authentication to Django. It can be integrated at various levels, from view to form to low-level API.

0
boatcoder On

More than a year after the last answer:

Django-two-factor-auth builds on django-otp and adds out of the box support for Google Authenticator, Twilio SMS, backup codes. Very impressive.

0
cornelinux On

You could use an existing multifactor authentication backend like LinOTP or privacyidea. I created a django-plugin writeup.