简体   繁体   English

在 Ruby / Python 中实现 Umbraco/ASP.NET 密码验证脚本

[英]Implement an Umbraco/ASP.NET password validation script in Ruby / Python

I have exported about 1K users from an Umbraco database.我从 Umbraco 数据库中导出了大约 1K 用户。 We have emails and hashed_passwords for each.我们每个都有电子邮件和 hashed_passwords。 There appears to be no per-user salt.似乎没有每个用户的盐。

Umbraco project version is 7.4 with the following (default) settings: Umbraco 项目版本为 7.4,具有以下(默认)设置:

<membership defaultProvider="UmbracoMembershipProvider" userIsOnlineTimeWindow="15">
  <providers>
    <clear />
    <add name="UmbracoMembershipProvider" type="Umbraco.Web.Security.Providers.MembersMembershipProvider, Umbraco.Web" minRequiredNonalphanumericCharacters="0" minRequiredPasswordLength="5" useLegacyEncoding="false" enablePasswordRetrieval="false" enablePasswordReset="false" requiresQuestionAndAnswer="false" defaultMemberTypeAlias="Member" passwordFormat="Hashed" allowManuallyChangingPassword="true" />
    <add name="UsersMembershipProvider" type="Umbraco.Web.Security.Providers.UsersMembershipProvider, Umbraco.Web" />
  </providers>
</membership>
<!-- Role Provider -->
<roleManager enabled="true" defaultProvider="UmbracoRoleProvider">
  <providers>
    <clear />
    <add name="UmbracoRoleProvider" type="Umbraco.Web.Security.Providers.MembersRoleProvider" />
  </providers>
</roleManager>
<machineKey validationKey="9FEB5*******************B7348B27A6C" decryptionKey="73934**************69366" validation="HMACSHA256" decryption="AES" />

Asp.net code used seems to be this one:使用的 Asp.net 代码似乎是这个:

https://referencesource.microsoft.com/#System.Web/Security/SQLMembershipProvider.cs,f37d42faca2b921e,references https://referencesource.microsoft.com/#System.Web/Security/SQLMembershipProvider.cs,f37d42faca2b921e,参考资料

I have setup this code in Ruby to properly encode the plain text password and compare it with the hashed passwords, so that users can login without having to reset their original plain text passwords:我在 Ruby 中设置了此代码,以正确编码纯文本密码并将其与散列密码进行比较,以便用户无需重置原始纯文本密码即可登录:

def encode_password(password, salt)

    require "base64"
    require "digest"

    bytes = ""
    password.each_char { |c| bytes += c + "\x00" }
    salty = Base64.decode64(salt)
    concat = salty+bytes
    sha256 = Digest::SHA256.digest(concat)
    encoded = Base64.encode64(sha256).strip()
    puts encoded
  end

But my problem is that I don't know which salt to use.但我的问题是我不知道该使用哪种盐。 From what I've been able to research here:根据我在这里能够研究的内容:

https://shazwazza.com/post/umbraco-passwords-and-aspnet-machine-keys https://shazwazza.com/post/umbraco-passwords-and-aspnet-machine-keys

Umbraco uses a single salt derived from the machineKey, but it's unclear which part exactly. Umbraco 使用从 machineKey 派生的单一盐,但不清楚具体是哪一部分。 And it's unclear if it should be part of the validationKey or the decryptionKey目前还不清楚它是否应该是validationKeydecryptionKey的一部分

the salt is not based on the machine key.盐不是基于机器密钥。 The blog post says:博客文章说:

The key used to hash the passwords is the generated salt we produce it is not the key part of the Machine Key用于 hash 的密钥是我们生成的盐,它不是机器密钥的关键部分

and

The part of the Machine Key that is used to hash the passwords is specifically the algorithm type.用于hash密码的机器密钥部分具体是算法类型。

So the only part of the machine key that is used is the algorithm type.因此,唯一使用的机器密钥部分是算法类型。

This method EncryptOrHashNewPassword is what creates the salt + password.此方法EncryptOrHashNewPassword是创建盐 + 密码的方法。 It then calls EncryptOrHashPassword with the provided salt to do the password hashing.然后它使用提供的盐调用EncryptOrHashPassword来进行密码散列。 All of that is called from this method HashPasswordForStorage which takes the fully hashed password along with the salt used to hash the password and stores both of them together as a string (base64 iirc).所有这些都是从这个方法HashPasswordForStorage调用的,它采用完全散列的密码以及用于 hash 密码的盐,并将它们一起存储为字符串(base64 iirc)。

When verifying the password, the salt is parsed from the stored string and is used to hash the incoming password to see if they match.验证密码时, 从存储的字符串中解析出salt,用于hash传入的密码,看是否匹配。 This unit test somewhat shows this 这个单元测试在某种程度上表明了这一点

That's pretty much what you would need to port to Ruby/Python.这几乎就是移植到 Ruby/Python 所需的内容。

For anyone who is looking to export their Umbraco passwords hashes to an alternate platform, this is the Python script that made it possible for us to do the comparison with plain text passwords entered at login time.对于希望将其 Umbraco 密码哈希导出到备用平台的任何人,这是 Python 脚本,它使我们能够与在登录时输入的纯文本密码进行比较。 Working flawlessly.工作完美无缺。

import base64
import hashlib
import hmac
import secrets
from typing import Tuple

def check_password(password: str, db_password: str) -> bool:
    """Check if password matches"""

    if not db_password.strip():
        raise ValueError("dbPassword cannot be none or empty")

    stored_hash_password, salt = stored_password(db_password)
    hashed = encrypt_or_hash_password(password, salt)
    return stored_hash_password == hashed


def stored_password(stored_string: str) -> Tuple[str, str]:
    """Return salt and password from stored_string"""
    if not stored_string.strip():
        raise ValueError("stored_string cannot be none or empty")

    salt = GenerateSalt()
    salt_len = len(salt)
    
    password = stored_string[salt_len :]
    salt = stored_string[0 : salt_len - 1]

    return password, salt


def GenerateSalt() -> str:
    """Return byte array with 24 length"""
    return secrets.token_hex(12)


def encrypt_or_hash_password(password: str, salt: str) -> str:
    """Return hashed password"""

    ##
    ## Bytes with 16 length repeated till 64 length (=== is for base64 padding)
    ##
    salt_bytes = base64.b64decode(salt + '===') * 4 

    ## WARN!!!!
    ## HACK TO MATCH C# UNICODE
    ##
    unicode_password = []
    for char in password:
        unicode_password += char
        unicode_password += chr(0)
    password_bytes = ''.join(unicode_password).encode()

    hash_bytes = hmac.new(salt_bytes, password_bytes, digestmod=hashlib.sha256).digest()
    return base64.b64encode(hash_bytes).decode()

print(
    check_password(
        "xxxxxx",
        "aOrcTkUrkb45kR6UA7Yv5Q==S++GZlit8lIxxx2rpHDwPt3dhSoEDa3HPsUg4hCpnWU=",
    )
)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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