使用Python对ASP.NET角色/成员身份创建的数据库中的原始用户名、哈希、salt进行身份验证
我们有一个当前应用程序,其中用户登录凭据存储在SQL Server数据库中。基本上,它们存储为纯文本用户名、密码散列和该散列的相关salt 这些都是由ASP.NET的成员/角色系统中的内置函数创建的。这是一行,用户名为“joe”,密码为“password”: joe,kDP0Py2QwEdJYtUX9cJABg==,OJF6H4KDXFGLU+oTDNFodCEfMA= 我已将此内容转储到CSV文件中,并尝试将其转换为Django的可用格式,该格式将密码存储为以下格式: [算法]$[盐]$[散列] 其中salt是一个普通字符串,hash是SHA1哈希的十六进制摘要 到目前为止,我已经能够确定ASP正在以base64格式存储这些散列和盐。上面这些值被解码成二进制字符串 我们使用reflector收集了ASP如何根据这些值进行身份验证:使用Python对ASP.NET角色/成员身份创建的数据库中的原始用户名、哈希、salt进行身份验证,asp.net,python,hash,passwords,Asp.net,Python,Hash,Passwords,我们有一个当前应用程序,其中用户登录凭据存储在SQL Server数据库中。基本上,它们存储为纯文本用户名、密码散列和该散列的相关salt 这些都是由ASP.NET的成员/角色系统中的内置函数创建的。这是一行,用户名为“joe”,密码为“password”: joe,kDP0Py2QwEdJYtUX9cJABg==,OJF6H4KDXFGLU+oTDNFodCEfMA= 我已将此内容转储到CSV文件中,并尝试将其转换为Django的可用格式,该格式将密码存储为以下格式: [算法]$[盐]$[散列
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);
}
因此,从DB中提取salt,b64将其解码为二进制表示。它对原始密码执行“GetBytes”操作,然后将其包含在内,首先是salt
然后对这个新字符串运行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())
我想知道是否有人能看到我的方法中的任何缺陷,或者能建议一种替代方法。也许您可以使用上面的算法和上面的已知密码和salt,在您的系统上生成哈希值?关于可能出现的问题,有两种想法 首先,来自反射的代码有三条路径:
- 如果passwordFormat为0,则按原样返回密码
- 如果passwordFormat为1,它将像python代码一样创建哈希
- 如果passwordFormat不是0或1,它将调用此。EncryptPassword()
0x00 0x70 0x00 0x61 0x00 0x73 0x00 0x73 0x00 0x77 0x00 0x6F 0x00 0x72 0x00 0x64
而不是:
0x70 0x61 0x73 0x73 0x77 0x6F 0x72 0x64
我希望这会有所帮助。当您将UTF16字符串转换为二进制时,python似乎正在插入字节顺序标记。NET字节数组不包含BOM,因此我使用了一些犹太区python,将UTF16转换为十六进制,删除前4个字符,然后将其解码为二进制 也许有更好的方法来删除BOM表,但这对我来说很有用 这里有一个经过:
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())
我相信您需要的编码被称为“utf-16le”,因此您不必手动杀死BOM@BryanRehbein您是对的,使用
password\u string='password'.encode(“utf-16-le”)
您可以完全省略utf16tobin解决方案。