1

I have a Django-based site (not yet launched, so there are no real users) using plain django.contrib.auth, and want to store passwords as plain-text, not salted SHA-1 hashes.

The question is what's the best approach to do this, hopefully, without patching (or monkey-patching) Django source code?

NOTE: I perfectly know this is certainly less secure. Plaintext is required to perform challenge-response auth, like CHAP for PPTP VPN, DIGEST-MD5 for IMAP4 and HTTP Digest for WebDAV-based file storage. So, I'm trading DB-level security with connection-level security.

Of course, I'm considering educating and encouraging users on using X.509 certificates (and not having any passwords), but this is not so easy.

Reversibly encrypting (obfuscating) passwords, and using some sort column-level permissions so the password will be INSERTable/UPDATEable, but not SELECTable by the web user (only accessible for some custom check function, like SELECT * FROM users WHERE 'somesha1hash' = USER_HMAC(id, 'salt')) so the passwords wont be "just there" is a good idea and I'll try to do it. Suggestions on securing plaintext data are warmly welcomed, but what I mostly want to hear is how to hack the way passwords are stored.

drdaeman
  • 11,159
  • 7
  • 59
  • 104
  • 4
    Why would you do that? It's not safe. If you do, don't forget to warn your users. I know I wouldn't subscribe to a website doing that voluntarily. – Loïc Wolff Jul 09 '09 at 11:21
  • 1
    I know this is less secure. Plaintext is required to perform challenge-response auth, like CHAP for PPTP VPN and HTTP Digest for WebDAV-based personal file storage. So, I'm trading DB-level security with connection-level security. – drdaeman Jul 09 '09 at 11:28
  • 1
    Thus you are making it even worse. No only will access to your App be compromised, but at the same time numerous other accounts you users may have. DON'T DO IT. – Ber Jul 09 '09 at 11:35
  • 1
    So, any suggestions on performing PPP's CHAP or SASL's DIGEST-MD5 _without_ known plaintext, then? Of course, I'm considering educating and encouraging users on using X.509 certificates (and not having any passwords), but this is not so easy. – drdaeman Jul 09 '09 at 11:42
  • If you need to authenticate against a different kind of auth server, why not write a custom authentication backend? The Django docs outline how to do this fairly well. – Ryan Duffield Jul 09 '09 at 12:50
  • No, Django website is a master authentication source. It handles user registration and so on. I just want FreeRADIUS, IMAPd and my homebrewn WebDAV implemenation to use the same accounts. – drdaeman Jul 09 '09 at 13:11

3 Answers3

6

In Django, it's not that hard: you simply have to write an authentication backend, that will authenticate users against password stored in plaintext.

That said, you should never store passwords in plaintext.
The main point is that people tend to use the same password over and over again and therefore, using plaintext in your site you put your users at risks for an attacker to get to their bank account.
Jeff Atwood wrote a nice post, about this topic, You're Probably Storing Passwords Incorrectly; I suggest you reading it, because it will explain issues about plaintext in passwords in a much better way than me.
At least, you should encourage your users to use a different password from their "secure" ones; for instance, you could simply generate new random passwords, even if this approach has its own limitations, too.

Another approach, that could be much more secure: write your authentication backend, that will validate against (for instance) the WebDAV storage. You do not store the passwords anywhere in your system - you simply pass them through. I do not know if it may work in your case (especially if you have to authenticate against several sources) but at least you can give it a try.

rob
  • 36,896
  • 2
  • 55
  • 65
5

There is a bunch of perfectly good scenarios for keeping passwords plain text (kids game sites etc). It's actually pretty easy to do.

In your settings add:

PASSWORD_HASHERS = ('wereallfriendsinunikittyland.PlainTextPassword',)    

Than create a file wereallfriendsinunikittyland.py.

from django.contrib.auth.hashers import BasePasswordHasher

class PlainTextPassword(BasePasswordHasher):
    algorithm = "plain"

    def salt(self):
        return ''

    def encode(self, password, salt):
        assert salt == ''
        return password

    def verify(self, password, encoded):
        return password == encoded

    def safe_summary(self, encoded):
        return OrderedDict([
            (_('algorithm'), self.algorithm),
            (_('hash'), encoded),
        ])
fmalina
  • 6,120
  • 4
  • 37
  • 47
4

Don't do this. It violates basic security principles. Better not have password at all than doing this.

Regarding your updated question: store those external access password encrypted in a seperate table (they may not all be the same, anyway). User user's password to generated salted key for this encryption. Then, wenn she logs in, you app may decrypt and use those keys.

This very hard indeed to get right. Good luck!

Ber
  • 40,356
  • 16
  • 72
  • 88
  • 1
    Thank you for suggestion! Unfortunately, this requires user to log in onto website first, then temporarily keep the decryption key somewhere to pass it to a RADIUS server or POP3/IMAPd, and only then PPTP connections will be possible, but just for some time. And users will have to remember two passwords instead of one. Sounds quite hard. I'm obviously thinking about promoting X.509/TLS auth, but unfortunately a lot of users are too used to login-password scheme and just won't grasp public-key concept too easily. – drdaeman Jul 09 '09 at 12:01
  • 1
    @drdaeman, you are already making your users remember multiple passwords, because they can't reuse the one you're storing in cleartext. – Kevin Jul 09 '09 at 14:25
  • sometimes plaintext passwords needed. for example in CHAP auth – eri Sep 09 '18 at 10:43