如何在Python中重实现Microsoft SQL Server的PWDENCRYPT/PWDCOMPARE?
Django自定义密码哈希器适配SQL Server PWDENCRYPT哈希验证
我们团队近期用Python+Django重构原有的.NET平台,上线前要迁移用户数据。原系统依赖SQL Server自带的PWDENCRYPT生成密码哈希、PWDCOMPARE做验证,为了让用户不用重置密码就能直接登录,必须实现一个自定义Django密码哈希器来兼容这套逻辑。
一开始查微软官方文档,发现PWDENCRYPT的底层实现几乎没有详细说明,还被标记为旧版函数,明确说未来可能弃用,推荐使用支持更多算法的HASHBYTES。翻了不少相关内容找思路,但部分解释和示例存在错误,绕了好多弯路,甚至一度想放弃。后来同事找到了关键突破口——密码必须先转换为UTF-16LE编码,这对熟悉Windows环境的人来说可能是常识,但我们一开始完全忽略了这个细节。
下面是最终可用的自定义哈希器代码,直接集成到Django项目即可:
from django.contrib.auth.hashers import BasePasswordHasher import hashlib import os class MSSQLPWDENCRYPTHasher(BasePasswordHasher): algorithm = "mssql_pwdencrypt" def verify(self, password, encoded): # SQL Server的PWDENCRYPT哈希格式:0x0100 + 4字节salt + 20字节MD5哈希值 encoded_hex = encoded[2:] # 移除开头的0x前缀 encoded_bytes = bytes.fromhex(encoded_hex) # 提取salt和存储的哈希值 salt = encoded_bytes[1:5] stored_hash = encoded_bytes[5:25] # 按规则计算哈希:密码转UTF-16LE + salt,再做MD5 password_utf16le = password.encode('utf-16le') computed_hash = hashlib.md5(password_utf16le + salt).digest() return computed_hash == stored_hash def encode(self, password, salt=None): # 若需要生成兼容PWDENCRYPT的哈希可使用此方法,我们主要用验证逻辑 if salt is None: salt = os.urandom(4) # 生成4字节随机salt password_utf16le = password.encode('utf-16le') computed_hash = hashlib.md5(password_utf16le + salt).digest() # 拼接成SQL Server格式的哈希字符串 return f"0x0100{salt.hex()}{computed_hash.hex()}"
将这个哈希器添加到Django配置的PASSWORD_HASHERS列表中,放在默认哈希器之前:
PASSWORD_HASHERS = [ 'your_app_name.hashers.MSSQLPWDENCRYPTHasher', # 替换为实际路径 'django.contrib.auth.hashers.PBKDF2PasswordHasher', # 保留其他默认哈希器... ]
这样迁移过来的用户就能直接使用原密码登录,登录成功后Django会自动用默认的强哈希算法重新加密密码并存入数据库,后续就无需再依赖这个自定义哈希器了。
内容的提问来源于stack exchange,提问作者decibyte
相关产品推荐
相关产品推荐

