数字签名的应用通常不包括C. 密码存储✅
理由:数字签名用于验证数据来源的真实性、完整性和不可否认性,其核心是使用私钥签名、公钥验签,适用于身份认证、文档签署、软件分发等场景。而密码存储应采用加盐哈希(如 bcrypt、scrypt、Argon2)等单向不可逆方式,目的是防止明文泄露和彩虹表攻击;若用数字签名存储密码,不仅违背设计目的(签名可被公钥验证,但不应“可验证原始密码”),还可能引入私钥管理风险,且无法实现密码的单向保护。
常见数字签名典型应用包括:
- SSL/TLS 证书(验证服务器身份)
- 电子合同与政务签章(法律效力保障)
- APK/APP代码签名(Android/iOS 应用完整性校验)
- 软件发布签名(如 Linux 内核模块、GPG 签名)
- S/MIME 或 PGP 电子邮件签名(发件人身份认证)
❌ 密码存储不属于数字签名的应用范畴,属于密码学中的密钥派生与哈希保护领域。
数字签名不能用于密码存储,根本原因在于二者的设计目标、安全模型和使用方式存在本质冲突:
🔹1. 设计目标不同
- 数字签名:解决身份认证、数据完整性与不可否认性问题。它要求“可验证”——任何人持有公钥即可验证签名是否由对应私钥生成,但不隐藏原始消息内容(签名对象通常是明文摘要,而非保密数据)。
- 密码存储:核心目标是单向保护与抗逆向——即使数据库泄露,攻击者也无法从存储值恢复原始密码。这要求不可逆性、抗碰撞性、抗预计算(如彩虹表),且必须引入随机性(加盐)。
🔹2. 安全模型冲突
- 数字签名依赖私钥保密、公钥公开,验签过程天然暴露“该消息曾被某私钥签署”,若用它“存储密码”,相当于将“密码是否匹配”变成一个可被任意方(拥有公钥者)主动验证的公开操作,严重违背最小权限与保密原则。
- 更危险的是:若攻击者获取公钥和签名值,虽不能直接恢复密码,但可进行离线暴力/字典验证(即:猜一个密码 → 计算其摘要 → 用公钥验签是否匹配),而哈希加盐方案通过慢哈希(如 bcrypt)大幅增加验证成本,签名则无此防护。
🔹3. 技术机制不匹配
- 数字签名 ≠ 加密:签名是对消息摘要(如 SHA-256 值)的私钥运算,不改变原始密码的可枚举性;它不提供密钥派生(KDF)、不引入计算延迟、无盐值绑定,无法抵御批量爆破。
- 哈希加盐方案(如
bcrypt(password, salt, cost)):
✅ 强制唯一盐值(防彩虹表)
✅ 可调代价因子(防暴力加速)
✅ 单向函数(无法从输出反推输入)
✅ 专为密码场景标准化(OWASP 推荐)
✅ 正确做法:密码存储应使用专用密钥派生函数(KDF),如 bcrypt、scrypt、Argon2 或 PBKDF2;而数字签名仅用于“证明某主体对某数据的认可”,如签署登录挑战、证书、交易等。
# ❌ 错误示例:用 RSA 签名“存储”密码(极度危险!)fromcryptography.hazmat.primitives.asymmetricimportpadding,rsafromcryptography.hazmat.primitivesimporthashes private_key=rsa.generate_private_key(public_exponent=65537,key_size=2048)password=b"123456"signature=private_key.sign(password,padding.PKCS1v15(),hashes.SHA256())# 危险!签名暴露验证入口# ✅ 正确示例:用 bcrypt 安全存储密码importbcrypt password=b"123456"salt=bcrypt.gensalt(rounds=12)hashed=bcrypt.hashpw(password,salt)# 单向、加盐、慢计算