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