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

时间:2019-11-13 16:47:41

标签: authentication cryptography

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

要求:为简单起见,我们假设一个带有一个User模型的简单后端,该模型只有一个字段:favorite_number

  • 用户可以在后端CRUD User模型。
  • 用户无法对其他用户的User模型进行欺诈。

潜在的解决方案

  • Alice在她的移动设备上生成一个私钥/公钥对。她将私钥安全地保存在设备上。
  • Alice向后端发出网络请求(例如RESTful POST请求),并具有以下负载:
{
  "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..      |
  • 爱丽丝想读她最喜欢的电话号码:
    • Alice将GET /api/get_nonce?public_key={Alice's public key}发送到后端
    • 后端在数据库中查找包含Alice的公钥的行,并仅返回其signature
    • 爱丽丝用她的本地私钥解密signature,并返回42
  • Bob想要读取Alice的收藏夹号码,他呼叫相同的端点GET /api/get_nonce?public_key={Alice's public key},获得Alice的收藏夹数字签名,但无法解密。
  • Bob想要修改Alice的收藏夹号码,但无法修改,因为他无法计算favorite_number消息的签名。

注意事项(我可以接受)

  • 如果Alice丢失了手机或卸载了该应用程序,则她在后端的所有帐户信息都将丢失。

其他假设

  • 除后端(和数据库管理员)本身以外,其他任何人都不能直接访问数据库。 (@kelalaka提出的澄清要求)。但这与身份验证无关。

问题:此身份验证方案可行吗?您看到任何大的安全漏洞吗?

1 个答案:

答案 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,或任何类似的经过加密和身份验证的传输。