Skip to content
This repository has been archived by the owner on Mar 9, 2022. It is now read-only.

Latest commit

 

History

History
99 lines (69 loc) · 3.67 KB

README.mdown

File metadata and controls

99 lines (69 loc) · 3.67 KB

django-twofactor

A django app that allows supplementing the default django.contrib.auth login system with two-factor authentication using the Time-Based One-Time Password (TOTP) Algorithm spec (RFC 6238).

Google Authenticator is currently the primary support target for tokens, but any TOTP (soft?) token that allows using a server-generated seed should work.

Some notes:


Current status

This app is a work in progress. It is not much farther than "proof of concept," however. Clone the source and look at twofactor_demo/README.mdown for a quick demo (including steps on how to set it up).

The basics work:

  • If the special adminsite subclass is used, all login forms are replaced with one that has an optional "Auth Code" field. (Users with two-factor auth enabled will be required to enter this.)
  • In the admin, a "Two-factor Authentication" link shows up next to the "Change password" link. From here, a user may enable two-factor auth (if it is not enabled), reset their auth token (to allow migration to a new device), or disable two-factor auth (if it is enabled).

What does not work:

  • (Optional) backup codes or some ability to reset your auth token (or even simply log in) if you have lost your token. Optional because in some usecases this is a feature for high security that require manual intervention (support call to have a human verify and reset). FWIW, Google does provide this in the form of temporary, one-time-use codes that are received when two-factor authentication is turned on.

Dependencies

Optionally, for performance:

  • PyCrypto -- See PyCrypto section below, under Security Considerations.

Security Considerations

Section 5.1 of RFC 6238 "recommends" that the shared secret key (i.e. the "seed" for the time-based generator) be stored securely in the validation system (i.e., the server) and specifies encrypting the values until their use is necessary.

The key cannot be hashed (as with a password) because the raw value of the key is required to seed the generator. A single round of AES against settings.SECRET_KEY is used (with a randomly-generated seed appended to SECRET_KEY) as the encryption passphrase so that the value can be decrypted at validation time.

This works sort of like this:

stored_seed = salt + "$" + hexlify(AES(
    key = sha256(SECRET_KEY + salt),
    value = raw_seed
))
# i.e. 'CYM5yCSZ9Ybyu1dq$6cc094ca2e1eb46122d84ae877fff885'

This isn't perfect, but it obscures the values in the database in the event the database is compromised but settings.SECRET_KEY has not been.

PyCrypto

A copy of pyaes is bundled with this app. If PyCrypto is installed, that library's C-compiled extensions will be used instead of the (extremely slow) native Python AES implementation.