简体   繁体   中英

Migrating ASP.NET membership users to Django without resetting passwords?

I've got a system that was partially written by someone else and is a complete maintenance nightmare for such a small app. I've finally been given changes which justifies just rewriting the horrible mess so I am moving it to Django.

Before I take the plunge, I've been trying to move over the password hash and salt into the Django auth tables [sha1]$[salt]$[hash] but can't get it to hash properly (resetting passwords isn't really an option).

Here is what I've been able to find out so far:

  • ASP.NET stores the hash as base64 string and uses a base64 salt (before hash)
  • I can obviously reverse the base64 hash to a byte array
  • Django uses a hexdigest, I tried BitConverter.ToString but they hash differently

Am I fighting a losing battle here? Would it be better to write a method in Django to hash as ASP.NET does?

Any help appreciated,

Thomas

The only real options you have here to avoid a password reset in the middle is to:

  1. Write a hash translation algorithm to transfer the Asp.Net hash into the hexdigest hash. Good luck with this one. If you pull it off, write a paper about it.
  2. Rewrite the Django hashing algorithm to hash identically to the Asp.Net algorithm. This one should be the easiest to pull off, but it's still going to have its traps and pitfalls in the process.

You could also attempt to reverse engineer the passwords, but if you're successful in doing that it sort of makes the hashing algorithm pointless IMO.

Create a new module with the following Django password hasher to handle ASP.net (sha1) passwords:

import hashlib
import base64

from django.contrib.auth.hashers import (BasePasswordHasher, mask_hash)
from django.utils.datastructures import SortedDict
from django.utils.encoding import force_bytes
from django.utils.crypto import constant_time_compare
from django.utils.translation import ugettext_noop as _

def utf16tobin(s):
    return s.encode('hex')[4:].decode('hex')

class MSSHA1PasswordHasher(BasePasswordHasher):
    """
    ASP.NET hasher
    """
    algorithm = "mssha1"

    def encode(self, password, salt):
        assert password is not None
        assert salt and '$' not in salt
        pwdenc = password.encode('utf16')
        pwdenc = utf16tobin(pwdenc)
        saltdecode = base64.b64decode(salt)
        m = hashlib.sha1()
        m.update(saltdecode)
        m.update(pwdenc)
        hash = base64.b64encode(m.digest())
        return "%s$%s$%s" % (self.algorithm, salt, hash)

    def verify(self, password, encoded):
        algorithm, salt, hash = encoded.split('$', 2)
        assert algorithm == self.algorithm
        encoded_2 = self.encode(password, salt)
        return constant_time_compare(encoded, encoded_2)

    def safe_summary(self, encoded):
        algorithm, salt, hash = encoded.split('$', 2)
        assert algorithm == self.algorithm
        return SortedDict([
            (_('algorithm'), algorithm),
            (_('salt'), mask_hash(salt, show=2)),
            (_('hash'), mask_hash(hash)),
            ])

Add the module name to your settings file in the PASSWORD_HASHERS list (see https://docs.djangoproject.com/en/1.4/topics/auth/ for details).

Migrate the ASP.net salt and password into the Django password field like this:

user.password = "mssha1$" + old_membership.passwordsalt + "$" + old_membership.password

Users can then login to your Django app with their existing ASP.net passwords. Once they've logged in successfully, Django will automatically upgrade their passwords to the latest algorithm, eg PBKDF2.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM