更新:
我已将此链接添加到我的其他答案中,如何在此为对JWT感兴趣的任何人对ASP.NET Web API使用JWT身份验证。
我们已经设法将HMAC身份验证应用于安全的Web API,并且工作正常。HMAC身份验证为每个使用者使用一个秘密密钥,使用者和服务器双方都知道该密钥对hmac散列消息,应该使用HMAC256。在大多数情况下,使用消费者的哈希密码作为秘密密钥。
该消息通常是根据HTTP请求中的数据甚至添加到HTTP标头中的自定义数据构建的,该消息可能包括:
- 时间戳:请求发送的时间(UTC或GMT)
- HTTP动词:GET,POST,PUT,DELETE。
- 发布数据和查询字符串,
- 网址
在后台,HMAC身份验证将是:
消费者在构建签名(hmac哈希的输出)后,将HTTP请求发送到Web服务器,这是HTTP请求的模板:
User-Agent: {agent}
Host: {host}
Timestamp: {timestamp}
Authentication: {username}:{signature}
GET请求的示例:
GET /webapi.hmac/api/values
User-Agent: Fiddler
Host: localhost
Timestamp: Thursday, August 02, 2012 3:30:32 PM
Authentication: cuongle:LohrhqqoDy6PhLrHAXi7dUVACyJZilQtlDzNbLqzXlw=
哈希以获取签名的消息:
GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
带查询字符串的POST请求示例(以下签名不正确,仅是示例)
POST /webapi.hmac/api/values?key2=value2
User-Agent: Fiddler
Host: localhost
Content-Type: application/x-www-form-urlencoded
Timestamp: Thursday, August 02, 2012 3:30:32 PM
Authentication: cuongle:LohrhqqoDy6PhLrHAXi7dUVACyJZilQtlDzNbLqzXlw=
key1=value1&key3=value3
散列消息以获取签名的消息
GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
key1=value1&key2=value2&key3=value3
请注意,表单数据和查询字符串应顺序排列,因此服务器上的代码将获取查询字符串和表单数据以构建正确的消息。
当HTTP请求到达服务器时,将实施身份验证操作过滤器以解析请求以获取信息:HTTP动词,时间戳,uri,表单数据和查询字符串,然后基于这些信息构建带有秘密的签名(使用hmac哈希)服务器上的密钥(哈希密码)。
秘密密钥是从数据库中获取的,并带有请求中的用户名。
然后,服务器代码将请求上的签名与构建的签名进行比较;如果相等,则认证通过,否则,认证失败。
构建签名的代码:
private static string ComputeHash(string hashedPassword, string message)
{
var key = Encoding.UTF8.GetBytes(hashedPassword.ToUpper());
string hashString;
using (var hmac = new HMACSHA256(key))
{
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
hashString = Convert.ToBase64String(hash);
}
return hashString;
}
那么,如何防止重放攻击?
为时间戳添加约束,例如:
servertime - X minutes|seconds <= timestamp <= servertime + X minutes|seconds
(servertime:请求到达服务器的时间)
并且,将请求的签名缓存在内存中(使用MemoryCache,应保持时间限制)。如果下一个请求带有与前一个请求相同的签名,则将被拒绝。
演示代码如下所示:https :
//github.com/cuongle/Hmac.WebApi