Unhashed passwords and django.contrib.auth

483 views
Skip to first unread message

Densetsu no Ero-sennin

unread,
Oct 2, 2007, 1:25:14 PM10/2/07
to django...@googlegroups.com
Hi,

I need to store unhashed user passwords in the DB. Is it possible with
django.contrib.auth? User.set_password method uses SHA-1 and it cannot be
overridden easily.

James Bennett

unread,
Oct 2, 2007, 2:04:43 PM10/2/07
to django...@googlegroups.com

So don't use set_password(), and avoid any built-in views which try to
hash things. And make sure your stakeholders are OK with the security
implications of storing passwords in plain text.

--
"Bureaucrat Conrad, you are technically correct -- the best kind of correct."

Densetsu no Ero-sennin

unread,
Oct 2, 2007, 2:38:00 PM10/2/07
to django...@googlegroups.com
On 3 October 2007 (Wed), James Bennett wrote:
> So don't use set_password(), and avoid any built-in views which try to
> hash things.

That's not all. I won't be able to use check_password(), which also calls
get_hexdigest(). And I'll have to reimplement ModelBackend because of that,
and possibly some other things. And I'll have to tweak admin interface to
make password changing work. I'd really like to see some cleaner and simpler
solution.

> And make sure your stakeholders are OK with the security
> implications of storing passwords in plain text.

Actually, this is exactly what they want, so I guess it can't be helped.

Malcolm Tredinnick

unread,
Oct 2, 2007, 2:51:10 PM10/2/07
to django...@googlegroups.com
On Wed, 2007-10-03 at 00:38 +0600, Densetsu no Ero-sennin wrote:
> On 3 October 2007 (Wed), James Bennett wrote:
> > So don't use set_password(), and avoid any built-in views which try to
> > hash things.
>
> That's not all. I won't be able to use check_password(), which also calls
> get_hexdigest(). And I'll have to reimplement ModelBackend because of that,
> and possibly some other things. And I'll have to tweak admin interface to
> make password changing work. I'd really like to see some cleaner and simpler
> solution.

I think you're colliding two separate problems together here: custom
authentication method and trying to use default methods to manage them.

The first problem is using something other than the default
authentication method (since you want to use a different storage
method). That is solve by writing a custom authentication backend. See
authentication.txt and search the wiki for some more information about
that. You can store the plain text password in a field in the user
profile or wherever you like. Then use the set_unusable_password()
method on the User model to avoid any accidental use of the default
system.

The second problem is try to co-opt the standard User model methods to
work with your custom auth scheme. That isn't what the default auth
system is designed to handle -- if you want to customise, it's done via
custom authentication backends and you are going to have to do the
management of that yourself.

However, some of this automatic use can be done via the fact that Python
is designed to allow methods and functions to be replaced. Import the
User model early enough in your code and then do things like

User.check_password = my_custom_check_password

and so on. No Django core changes required.

Regards,
Malcolm

Densetsu no Ero-sennin

unread,
Oct 2, 2007, 3:00:21 PM10/2/07
to django...@googlegroups.com
I've just thought that it would be nice if Django supported pluggable hash
functions for passwords. Something like this:

class Sha1Hash(object):
name = 'sha1'
def get_hex_digest(salt, raw_password):
import sha
return sha.new(salt + raw_password).hexdigest()

Then it would be possible to define custom hash functions:

class PlainText(object):
name = 'plain'
def get_hex_digest(salt, raw_password):
return raw_password

A variable in settings.py could be used to specify which function to use for
hashing new passwords (analogous to AUTH_PROFILE_MODULE):

PASSWORD_HASH_MODULE = 'some.module.PlainText'

Jacob Kaplan-Moss

unread,
Oct 2, 2007, 3:08:55 PM10/2/07
to django...@googlegroups.com
On 10/2/07, Densetsu no Ero-sennin <densetsu.no...@gmail.com> wrote:
> Then it would be possible to define custom hash functions:
>
> class PlainText(object):
> name = 'plain'
> def get_hex_digest(salt, raw_password):
> return raw_password

Django will never support storing passwords in plain text. In fact,
I'd go so far as saying that storing plaintext passwords *should* be a
major pain in the ass: storing unhashed passwords is one of the most
dangerous things a web developer can do.

Jacob

Malcolm Tredinnick

unread,
Oct 2, 2007, 3:16:37 PM10/2/07
to django...@googlegroups.com
On Wed, 2007-10-03 at 01:00 +0600, Densetsu no Ero-sennin wrote:
> I've just thought that it would be nice if Django supported pluggable hash
> functions for passwords.

This is one of those cases where it's micro-customisation without real
widespread benefit. As a rule, when you need control over the hash
function, you also need to touch other authentication things. This is
supported as custom authentication backends. It's not that we
necessarily say people should only use our default storage method, it's
just that it is very much a real edge case to want to change just that
one feature.

Adding settings for every fine-grained feature leads to settings bloat
and maintenance problems in the future.

So we've made the common use-case (store and validate a password,
without caring about the mechanics) and the harder stuff (any
customisation you like) possible.

Malcolm

Reply all
Reply to author
Forward
0 new messages