上下文:我有一个移动应用程序,但现在也没有,也不会实现传统的身份验证流程(电子邮件/密码,社交登录)。相反,我想利用非对称密钥加密。
要求:为简单起见,我们假设一个带有一个User
模型的简单后端,该模型只有一个字段:favorite_number
。
User
模型。User
模型进行欺诈。潜在的解决方案:
{
"public_key": {Alice's public key},
"favorite_number": 42,
"signature": sign_with_private_key(42)
}
其中sign_with_private_key(42)
是消息42
的签名,它是用爱丽丝的私钥签名的。
favorite_number
匹配,并将以下信息保存在其DB中(假定使用以下SQL):| public_key | favorite_number | signature |
| ---------- | --------------- | --------- |
| 0x... | 42 | 0x.. |
GET /api/get_nonce?public_key={Alice's public key}
发送到后端signature
列signature
,并返回42
。GET /api/get_nonce?public_key={Alice's public key}
,获得Alice的收藏夹数字签名,但无法解密。favorite_number
消息的签名。注意事项(我可以接受)
其他假设:
问题:此身份验证方案可行吗?您看到任何大的安全漏洞吗?
答案 0 :(得分:1)
这有点复杂。如果Alice有密钥对,则Alice可以简单地签署请求,而签署是就是身份验证。没有特别的理由来签名单个数据。只需自己签署请求即可。例如:
{
"request": {"message_id":123,"public_key":"...","favorite_number":42},
"signature": signature_of('{"message_id":123,"public_key":"...","favorite_number":42}')
}
请务必在请求中签名所有内容。
请注意,请求必须是一次性的,否则这是不安全的。一次性使用,是指时间戳记应包含在请求中,并且同一请求不应重复使用一次。您还可以使用消息计数器(特别是因为您只有一台可以连接的设备)。因此,服务器始终拒绝等于或小于为此用户发送的最后一个ID的消息ID。
您的方法很容易在另一个键上重复使用值。例如,我可以重用“ 42”并将其分配给其他东西,例如“ hated_number”。或者,我可以重播此消息并将爱丽丝的最爱号码更改为其他号码后将其重置为42。对整个请求进行签名是一种更好的方法,并且避免了许多此类问题(只要请求无法重用)。
如果Alice希望保护数据不受管理员的侵害,则她应该使用对称密钥对数据进行加密,但这与身份验证无关。
在可信任的传输方式下,一种更简单的实现方法是让Alice生成一个随机的256位标识符,并将其简单地用作身份验证。 256位标识符将始终足够稀疏,以至于无法猜测(猜测标识符与猜测AES-256密钥完全相同)。这样,仅知道标识符就足以认证请求。这仅在传输受信任的情况下有效,但与任何静态凭证(用户名+密码,令牌等)相同。所谓的受信任的传输,是指带有固定证书的HTTPS,或任何类似的经过加密和身份验证的传输。