Использование Python для аутентификации по необработанному имени пользователя, хешу, соли в БД, созданной ролями / членством ASP.NET - PullRequest
6 голосов
/ 06 ноября 2008

У нас есть текущее приложение, в котором учетные данные пользователя хранятся в БД SQL Server. Они, как правило, хранятся в виде обычного текстового имени пользователя, хэша пароля и связанной соли для этого хеша.

Все они были созданы встроенными функциями в системе членства / роли ASP.NET. Вот строка для пользователя с именем 'joe' и паролем 'password':

джо, kDP0Py2QwEdJYtUX9cJABg ==, OJF6H4KdxFLgLu + oTDNFodCEfMA =

Я выбросил этот материал в CSV-файл и пытаюсь перевести его в удобный для Django формат, который хранит свои пароли в следующем формате:

[алго] $ [соль] $ [хеш]

Если соль - простая строка, а хеш - это шестнадцатеричный дайджест хеша SHA1.

До сих пор мне удавалось установить, что ASP хранит эти хеши и соли в формате base64. Эти значения выше декодируют в двоичные строки.

Мы использовали рефлектор, чтобы выяснить, как ASP аутентифицируется по этим значениям:

internal string EncodePassword(string pass, int passwordFormat, string salt)
{
    if (passwordFormat == 0)
    {
        return pass;
    }
    byte[] bytes = Encoding.Unicode.GetBytes(pass);
    byte[] src = Convert.FromBase64String(salt);
    byte[] dst = new byte[src.Length + bytes.Length];
    byte[] inArray = null;
    Buffer.BlockCopy(src, 0, dst, 0, src.Length);
    Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
    if (passwordFormat == 1)
    {
        HashAlgorithm algorithm = HashAlgorithm.Create(Membership.HashAlgorithmType);
        if ((algorithm == null) && Membership.IsHashAlgorithmFromMembershipConfig)
        {
            RuntimeConfig.GetAppConfig().Membership.ThrowHashAlgorithmException();
        }
        inArray = algorithm.ComputeHash(dst);
    }
    else
    {
        inArray = this.EncryptPassword(dst);
    }
    return Convert.ToBase64String(inArray);
}

В сущности, извлекает соль из БД, а b64 декодирует ее в двоичное представление. Он выполняет «GetBytes» для необработанного пароля, а затем объединяет их, сначала солит.

Затем он запускает алгоритм SHA1 для этой новой строки, base64 кодирует ее и сравнивает со значением, хранящимся в базе данных.

Я попытался написать некоторый код, чтобы попытаться воспроизвести эти хеши в Python, и у меня не получается. Я не смогу использовать их в Django, пока не пойму, как это закончится. Вот как я тестирую:

import hashlib
from base64 import b64decode, b64encode

b64salt = "kDP0Py2QwEdJYtUX9cJABg=="
b64hash = "OJF6H4KdxFLgLu+oTDNFodCEfMA="
binsalt = b64decode(b64salt)
password_string = 'password'

m1 = hashlib.sha1()
# Pass in salt
m1.update(binsalt)
# Pass in password
m1.update(password_string)
# B64 encode the binary digest
if b64encode(m1.digest()) == b64hash:
    print "Logged in!"
else:
    print "Didn't match"
    print b64hash
    print b64encode(m1.digest())

Мне интересно, может ли кто-нибудь увидеть какие-либо недостатки в моем подходе или может предложить альтернативный метод. Возможно, вы можете воспользоваться приведенными выше алгоритмами, а также известным паролем и солью и создать хеш в своей системе?

Ответы [ 2 ]

8 голосов
/ 07 ноября 2008

Похоже, что Python вставляет маркер порядка байтов при преобразовании строки UTF16 в двоичный файл. Массив байтов .NET не содержит спецификацию, поэтому я создал гетто-Python, который превращает UTF16 в шестнадцатеричный код, удаляет первые 4 символа, а затем декодирует его в двоичный файл.

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

Вот тот, который проходит:

import hashlib
from base64 import b64decode, b64encode

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

b64salt = "kDP0Py2QwEdJYtUX9cJABg=="
b64hash = "OJF6H4KdxFLgLu+oTDNFodCEfMA="
binsalt = b64decode(b64salt)
password_string = 'password'.encode("utf16")
password_string = utf16tobin(password_string)

m1 = hashlib.sha1()
# Pass in salt
m1.update(binsalt + password_string)
# Pass in password
# B64 encode the binary digest
if b64encode(m1.digest()) == b64hash:
    print "Logged in!"
else:
    print "Didn't match"
    print b64hash
    print b64encode(m1.digest())
0 голосов
/ 06 ноября 2008

Две мысли о том, что может пойти не так.

Сначала код из отражения имеет три пути:

  • Если passwordFormat равен 0, он возвращает пароль как есть.
  • Если passwordFormat равен 1, он создает хеш, как ваш код Python.
  • Если значение passwordFormat отличается от 0 или 1, оно вызывает this.EncryptPassword ()

Откуда вы знаете, что вы хэшируете пароль, а не шифруете пароль с помощью этого. EncryptPassword ()? Вам может понадобиться отменить функцию-член EncryptPassword () и повторить ее. Это если у вас нет информации, которая гарантирует, что вы хэшируете пароль и не шифруете его.

Во-вторых, если он действительно хэширует пароль, вы можете посмотреть, что функция Encoding.Unicode.GetBytes () возвращает для строки «пароль», так как вы можете получить что-то вроде:

0x00 0x70 0x00 0x61 0x00 0x73 0x00 0x73 0x00 0x77 0x00 0x6F 0x00 0x72 0x00 0x64

вместо:

0x70 0x61 0x73 0x73 0x77 0x6F 0x72 0x64

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...