我刚刚开始在 .NET 中开发我的第一个 REST API。由于它将是无状态的,我将使用令牌进行身份验证:
基本思想(System.Security.Cryptography):
- AES 加密 + HMACSHA256 完整性
- 令牌数据将包含具有属性的对象:用户名、发行日期和超时
- 数据库将保存用户名、散列密码和 HMAC 散列
登录:
- 检查凭据是否有效(用户名,将散列密码与 db 值进行比较)
- 如果为真,加密数据对象
- 在生成的令牌上使用 HMAC 并将其存储到数据库
- 将令牌(不带 HMAC)返回给用户(cookie/字符串)
对需要身份验证的方法的请求:
- 用户随每个请求发送令牌
- 令牌被解密
- 如果过期,报错
- 如果未过期,则使用 HMAC 并将用户名 + 生成的哈希与 db 值进行比较
- 如果 db 检查有效,则用户已通过身份验证
在我看来,这种方法具有以下优点:
- 即使 db 被破坏,它也不包含实际的令牌(哈希无法反转......)
- 即使攻击者拥有令牌,他也无法通过更新字段来增加过期时间,因为过期日期在令牌本身中
现在首先,我想知道这是否是一个好方法。
除此之外,我仍然没有弄清楚,在服务器上存储 AES 和 SHA256 密钥的位置(我应该对它们进行硬编码吗?如果我将它们放入 web.config 或使用机器密钥,那么在负载平衡服务器的情况下我会遇到问题, ...)。
最后,我在哪里存储 AES IV 向量,因为 Crypto.CreateEncryptor 需要它来解密?这是否意味着用户必须在每个请求中发送令牌 + IV?
我希望这有任何意义,我提前感谢您的回答。
更新:
好的,现在我做了更多的研究并得出了这个解决方案:
- 令牌将包含最初指定的数据(用户名、发行日期和超时)
- 使用encrypt-then-mac生成令牌(它包括 AES 加密数据、IV 向量 + 用于身份验证的这 2 个值的标记,使用 HMACSHA265 生成)
- 令牌标签将被写入 db
- 如果满足以下条件,用户将被验证:
- 标签有效(令牌认证)
- 数据可以解密
- 令牌尚未过期
- 标签与数据库中写入的标签匹配
- 用户未在数据库中被阻止(令牌按需失效)
- 密钥将存储在 web.config 单独的部分中。每个服务器上都必须有相同的密钥(当然是每个应用程序)
我没有使用 FormsAuthenticationTicket,因为在 .NET 中存在以下问题:
- 相同的密钥用于不同的目的(用于查看状态、资源和表单的机器密钥)
- .NET 使用的 mac-then-encrypt不如 encrypt-then-mac 安全
- 在令牌过期之前没有内置方法使令牌失效