Перенос паролей из Drupal 7 в Django - PullRequest
10 голосов
/ 26 марта 2012

Я перевожу сайт с Drupal 7 на Django 1.4, включая текущих пользователей.Как я могу работать с паролями, которые были хэшированы Drupal?

Согласно this , Drupal 7 хэширует пароли, используя SHA-512 (они хранятся в виде строки, начинающейся с "$ S $ ").

Django 1.4 теперь содержит несколько опций для хранения паролей, по умолчанию SHA-256, но я не могу найти опцию для SHA-512,Хотя это приложение , по-видимому, позволяет использовать алгоритмы SHA2, я не уверен, что оно совместимо с Django 1.4 (поскольку 1.4 имеет гибкий хэш пароля).

Какой самый простой способсделать это?

ETA: я создал хеш-пароль, который имитирует алгоритм Drupal и упрощает миграцию.Поскольку я уже принял ответ, я не откажусь, но для тех, кто хочет в будущем выполнить миграцию Drupal на Django, код хранится в фрагментах Django и в виде GitHub.суть .

Ответы [ 4 ]

5 голосов
/ 26 марта 2012

Я не очень хорошо знаю Drupal, но полагаю, что пароли хранятся в хэше. Если это так, вам придется копировать пароли (я имею в виду, копировать их без изменений), и вам придется изменить способ, которым Django хеширует свои пароли, используя точно такой же способ Drupal, с той же солью безопасности.

Я действительно не знаю, как это сделать, но логика паролей содержится в объекте User. Например. функция User.set_password() (описанная здесь ) использует функцию make_password .

Я думаю, что после небольшого исследования вы найдете способ изменить его, но важно помнить, что функции должны быть равны! то есть:

drupal_hash (x) == django_hash (x) для каждого x в наборе разрешенных паролей.

EDIT:

При более глубоком рассмотрении django получает функцию has с функцией get_hasher . Теперь в версии 1.4 есть способ указать, как Django будет выбирать эту функцию. Взгляните на это: https://docs.djangoproject.com/en/dev/topics/auth/#how-django-stores-passwords

Наконец, чтобы создать собственную функцию, вы можете посмотреть, как это делается на MD5PasswordHasher . Это кажется действительно простым. Вы можете использовать библиотеку hashlib python для генерации алгоритмов sha-512.

Изменение метода кодирования потребует чего-то похожего на:

def encode(self, password, salt):
    assert password
    assert salt and '$' not in salt
    hash = hashlib.sha512(salt + password).hexdigest()
    return "%s$%s$%s" % (self.algorithm, salt, hash)
2 голосов
/ 17 июня 2012

Спасибо, Дэвид Робинсон, за ваш код.Это сделало мой день!Однако, похоже, у него есть недостаток: если Drupal решил использовать не «C», а «D» для количества итераций, это не удастся.Я немного исправил определение класса:

class DrupalPasswordHasher(BasePasswordHasher):
    algorithm = "S"
    iter_code = 'C'
    salt_length = 8

    def encode(self, password, salt, iter_code=None):
        """The Drupal 7 method of encoding passwords"""
        if iter_code == None:
            iterations = 2 ** _ITOA64.index(self.iter_code)
        else:
            iterations = 2 ** _ITOA64.index(iter_code)
        hash = hashlib.sha512(salt + password).digest()

        for i in range(iterations):
            hash = hashlib.sha512(hash + password).digest()

        l = len(hash)

        output = ''
        i = 0

        while i < l:
            value = ord(hash[i])
            i = i + 1

            output += _ITOA64[value & 0x3f]
            if i < l:
                value |= ord(hash[i]) << 8

            output += _ITOA64[(value >> 6) & 0x3f]
            if i >= l:
                break
            i += 1

            if i < l:
                value |= ord(hash[i]) << 16

            output += _ITOA64[(value >> 12) & 0x3f]
            if i >= l:
                break
            i += 1

            output += _ITOA64[(value >> 18) & 0x3f]

        longhashed = "%s$%s%s%s" % (self.algorithm, iter_code,
                                    salt, output)
        return longhashed[:54]

    def verify(self, password, encoded):
        hash = encoded.split("$")[1]
        iter_code = hash[0]
        salt = hash[1:1 + self.salt_length]
        return encoded == self.encode(password, salt, iter_code)
1 голос
/ 26 марта 2012

Вы сможете реализовать это, создав собственный подкласс BasePasswordHasher и добавив его к настройке PASSWORD_HASHERS.

hashlib в Python реализует sha512.

Страница , на которую Дэвид ссылается в вопросе , объясняет, как число итераций (16385 для Drupal 7) кодируется в хэше, но мне не ясно, как получить соль.

Редактировать : В комментарии к ответу @ santiago Дэвид говорит, что «соль - это 5-ый символ от 12-го в сохраненной строке Drupal».

0 голосов
/ 25 января 2017

Вот обновление отличного ответа Дэвида для Python 3, поскольку hashlib больше не принимает строки.Кроме того, сюда входит поддержка нечетных хэшей "U $ S $ *", которые, по-видимому, взяты из обновления, и я нашел их в своей базе данных drupal.

https://gist.github.com/skulegirl/bec420b5272b87d9e4dbd39e947062fc

И в качестве бонуса, вот код, который я использовал для импорта моего XML-файла пользовательских данных. (Я только что создал XML-файл с помощью экспорта SQL после выполнения запроса к таблице пользователей.)

import xml.etree.ElementTree as ET
from django.contrib.auth.models import User

tree = ET.parse('/PATH/TO/Users.xml')
root = tree.getroot()

for row in root:
    user_dict = {}
    for field in row:
        user_dict[field.attrib['name']] = field.text
    user = User.objects.create_user(user_dict['name'], user_dict['mail'])
    if user_dict['pass'][0] == '$':
        user_dict['pass'] = user_dict['pass'][1:]
    user.password = user_dict['pass']
    user.save()
...