Authentication 后端没有传统的身份验证机制,请改用加密技术

Authentication 后端没有传统的身份验证机制,请改用加密技术,authentication,cryptography,Authentication,Cryptography,上下文:我有一个移动应用程序,我没有也不会实施传统的身份验证流程(电子邮件/pw、社交登录)。相反,我想利用非对称密钥加密 需求:为了简单起见,让我们设想一个简单的后端,有一个用户模型,它只有一个字段:收藏夹编号 用户可以在后端CRUD用户模型 用户不能损坏另一用户的用户模型 潜在解决方案: Alice在她的移动设备上生成私钥/公钥对。她将私钥安全地保存在设备上 Alice使用以下负载向后端发出网络请求(比如RESTful POST请求): 其中sign\u with_private\u

上下文:我有一个移动应用程序,我没有也不会实施传统的身份验证流程(电子邮件/pw、社交登录)。相反,我想利用非对称密钥加密

需求:为了简单起见,让我们设想一个简单的后端,有一个
用户
模型,它只有一个字段:
收藏夹编号

  • 用户可以在后端CRUD
    用户
    模型
  • 用户不能损坏另一用户的
    用户
    模型
潜在解决方案

  • Alice在她的移动设备上生成私钥/公钥对。她将私钥安全地保存在设备上
  • Alice使用以下负载向后端发出网络请求(比如RESTful POST请求):
其中
sign\u with_private\u key(42)
是消息
42
的签名,用Alice的私钥签名

  • 后端接收上述有效负载,验证签名是否与公钥和
    收藏夹编号相匹配,并将以下信息保存在其数据库中(假设下面是SQL):
  • 爱丽丝想读她最喜欢的号码:
    • Alice将
      GET/api/GET\unce?public\u key={Alice的公钥}
      发送到后端
    • 后端在DB中查找带有Alice公钥的行,并仅返回其
      签名
    • Alice用她的本地私钥解密签名,它返回
      42
  • Bob想要读取Alice最喜欢的数字,他调用相同的端点
    GET/api/GET\unce?public\u key={Alice的公钥}
    ,GET的Alice最喜欢的数字签名,但无法解密
  • Bob想修改Alice最喜欢的号码,但无法修改,因为他无法计算
    最喜欢的号码
    消息的签名
注意事项(我可以接受):

  • 如果Alice丢失了她的手机或卸载了应用程序,那么她在后端的所有帐户信息都将丢失
其他假设

  • 除了后端(和数据库管理员)本身之外,其他方无法直接访问数据库。(由@kelalaka提出澄清请求)。但这与身份验证无关

问题:此身份验证方案可行吗?你有没有发现什么大的安全漏洞?

这感觉有点太复杂了。如果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”并将其分配给其他对象,如“讨厌的号码”。或者我可以重播此消息,并在Alice将其更改为其他对象后将其最喜欢的号码重置为42。对整个请求进行签名是一种更好的方法,可以避免许多此类问题(只要请求不能重用)

如果Alice希望对管理员保护数据,那么她应该使用对称密钥加密数据,但这与身份验证无关


如果传输是可信的,一种更简单的实现方法是让Alice生成一个随机的256位标识符,并简单地将其用作身份验证。256位标识符将始终足够稀疏,以至于无法使用(猜测标识符与猜测AES-256密钥完全相同)。这样,只需知道标识符就足以对请求进行身份验证。这仅在传输受信任时有效,但与任何静态凭据(用户名+密码、令牌等)相同。所谓可信传输,我指的是带有固定证书的HTTPS,例如,或任何类似加密和认证的传输。

签名可以验证,因此使用Alice公钥,DB的攻击者可以推断42是Alice签名的。如果Bob发送
GET/api/GET_nonce?public_key={Alice的公钥}
,假设Bob已经知道Alice的公钥。后端将返回Alice的签名,Bob可以验证它确实是Alice的,但Bob无法知道它是42。我在表上清楚地看到42。对,但我认为42存储在DB中,但后端只返回该DB的
签名
列。这就是我的观点,攻击者下载或访问DB,或者,半诚实的数据库管理员可以提取此信息。谢谢。你能详细说明一下你签署整个请求的意思吗?HTTP头和正文是什么样子的?用一个例子更新了。也就是说,我倾向于256位随机标识符而不是签名,并将消息完整性留给传输,而不是放在消息中。获取准确的签名可能非常棘手。我的首选是选择两个256位的值。使用第一个作为标识符,使用第二个来加密数据。这样,只有Alice可以更改数据(因为只有Alice和服务器可以访问标识符),并且只有Alice可以读取数据(因为只有Alice可以访问密钥)。感谢您提供的示例,明白了。我用一个256位的值来理解你的观点。但是我觉得使用两个256位的值(一个作为标识符,一个作为
| public_key | favorite_number | signature |
| ---------- | --------------- | --------- |
| 0x...      | 42              | 0x..      |
{
  "request": {"message_id":123,"public_key":"...","favorite_number":42},
  "signature": signature_of('{"message_id":123,"public_key":"...","favorite_number":42}')
}