是什么导致带有 HMAC 身份验证的 WebApi 只能工作一次?
What could cause WebApi with HMAC Authentication to only work once?
我有一个 C# MVC 项目,我最近向其中添加了 WebApi。我已经使用 HMAC 身份验证保护 API,并且正在使用 CustomDelegatingHandler 将授权添加到请求的 header。
我已经在另一个项目上使用相同的代码成功地完成了这项工作,而且它有效。但是在这个新项目中,身份验证只工作一次,然后由于 "Unauthorized",对 API 的所有其他调用都会失败。这只发生在我们的 development/test 服务器上,而不是在我的本地机器上 运行 2017 年 Visual Studio 的项目。
什么可能导致这种奇怪的行为?
这是我正在使用的 CustomDelegatingHandler:
public class CustomDelegatingHandler : DelegatingHandler
{
private string APPId = "";
private string APIKey = "";
public CustomDelegatingHandler(string appid, string apikey)
{
APPId = appid;
APIKey = apikey;
}
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpResponseMessage response = null;
string requestContentBase64String = string.Empty;
string requestUri = System.Web.HttpUtility.UrlEncode(request.RequestUri.AbsoluteUri.ToLower());
string requestHttpMethod = request.Method.Method;
//Calculate UNIX time
DateTime epochStart = new DateTime(1970, 01, 01, 0, 0, 0, 0, DateTimeKind.Utc);
TimeSpan timeSpan = DateTime.UtcNow - epochStart;
string requestTimeStamp = Convert.ToUInt64(timeSpan.TotalSeconds).ToString();
//create random nonce for each request
string nonce = Guid.NewGuid().ToString("N");
//Checking if the request contains body, usually will be null wiht HTTP GET and DELETE
if (request.Content != null)
{
byte[] content = await request.Content.ReadAsByteArrayAsync();
MD5 md5 = MD5.Create();
//Hashing the request body, any change in request body will result in different hash, we'll incure message integrity
byte[] requestContentHash = md5.ComputeHash(content);
requestContentBase64String = Convert.ToBase64String(requestContentHash);
}
//Creating the raw signature string
string signatureRawData = String.Format("{0}{1}{2}{3}{4}{5}", APPId, requestHttpMethod, requestUri, requestTimeStamp, nonce, requestContentBase64String);
var secretKeyByteArray = Convert.FromBase64String(APIKey);
byte[] signature = Encoding.UTF8.GetBytes(signatureRawData);
using (HMACSHA256 hmac = new HMACSHA256(secretKeyByteArray))
{
byte[] signatureBytes = hmac.ComputeHash(signature);
string requestSignatureBase64String = Convert.ToBase64String(signatureBytes);
//Setting the values in the Authorization header using custom scheme (amx)
request.Headers.Authorization = new AuthenticationHeaderValue("amx", string.Format("{0}:{1}:{2}:{3}", APPId, requestSignatureBase64String, nonce, requestTimeStamp));
}
response = await base.SendAsync(request, cancellationToken);
return response;
}
}
我们有一个类似的问题,结果证明与客户端与服务器的时间戳有关。
通过检查请求是否在允许的时间内解决了问题(server-side):
(a > b ? a-b : b-a) > maxtime
对比 a - b > maxtime
如果b > a,是一个unsigned long (ulong),该值变得很大,从而触发无效请求条件。
1522896501 - 1522896502 > 300(18446744073709551615 是计算出来的)
我有一个 C# MVC 项目,我最近向其中添加了 WebApi。我已经使用 HMAC 身份验证保护 API,并且正在使用 CustomDelegatingHandler 将授权添加到请求的 header。
我已经在另一个项目上使用相同的代码成功地完成了这项工作,而且它有效。但是在这个新项目中,身份验证只工作一次,然后由于 "Unauthorized",对 API 的所有其他调用都会失败。这只发生在我们的 development/test 服务器上,而不是在我的本地机器上 运行 2017 年 Visual Studio 的项目。
什么可能导致这种奇怪的行为?
这是我正在使用的 CustomDelegatingHandler:
public class CustomDelegatingHandler : DelegatingHandler
{
private string APPId = "";
private string APIKey = "";
public CustomDelegatingHandler(string appid, string apikey)
{
APPId = appid;
APIKey = apikey;
}
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpResponseMessage response = null;
string requestContentBase64String = string.Empty;
string requestUri = System.Web.HttpUtility.UrlEncode(request.RequestUri.AbsoluteUri.ToLower());
string requestHttpMethod = request.Method.Method;
//Calculate UNIX time
DateTime epochStart = new DateTime(1970, 01, 01, 0, 0, 0, 0, DateTimeKind.Utc);
TimeSpan timeSpan = DateTime.UtcNow - epochStart;
string requestTimeStamp = Convert.ToUInt64(timeSpan.TotalSeconds).ToString();
//create random nonce for each request
string nonce = Guid.NewGuid().ToString("N");
//Checking if the request contains body, usually will be null wiht HTTP GET and DELETE
if (request.Content != null)
{
byte[] content = await request.Content.ReadAsByteArrayAsync();
MD5 md5 = MD5.Create();
//Hashing the request body, any change in request body will result in different hash, we'll incure message integrity
byte[] requestContentHash = md5.ComputeHash(content);
requestContentBase64String = Convert.ToBase64String(requestContentHash);
}
//Creating the raw signature string
string signatureRawData = String.Format("{0}{1}{2}{3}{4}{5}", APPId, requestHttpMethod, requestUri, requestTimeStamp, nonce, requestContentBase64String);
var secretKeyByteArray = Convert.FromBase64String(APIKey);
byte[] signature = Encoding.UTF8.GetBytes(signatureRawData);
using (HMACSHA256 hmac = new HMACSHA256(secretKeyByteArray))
{
byte[] signatureBytes = hmac.ComputeHash(signature);
string requestSignatureBase64String = Convert.ToBase64String(signatureBytes);
//Setting the values in the Authorization header using custom scheme (amx)
request.Headers.Authorization = new AuthenticationHeaderValue("amx", string.Format("{0}:{1}:{2}:{3}", APPId, requestSignatureBase64String, nonce, requestTimeStamp));
}
response = await base.SendAsync(request, cancellationToken);
return response;
}
}
我们有一个类似的问题,结果证明与客户端与服务器的时间戳有关。
通过检查请求是否在允许的时间内解决了问题(server-side):
(a > b ? a-b : b-a) > maxtime
对比 a - b > maxtime
如果b > a,是一个unsigned long (ulong),该值变得很大,从而触发无效请求条件。
1522896501 - 1522896502 > 300(18446744073709551615 是计算出来的)