什么可能导致使用HMAC身份验证的WebApi只能工作一次?

时间:2017-10-30 22:22:27

标签: c# asp.net-web-api hmac

我有一个C#MVC项目,我最近添加了WebApi。我已使用HMAC身份验证保护API,并使用CustomDelegatingHandler将授权添加到请求的标头。

我已经使用相同的代码在另一个项目上成功完成了这项工作。但是在这个新项目中,身份验证只能运行一次,然后由于" Unauthorized"而对API的每次其他调用都会失败。这只发生在我们的开发/测试服务器上,而不是在我在Visual Studio 2017中运行项目的本地机器上。

什么可能导致这种奇怪的行为?

以下是我使用的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;
    }
}

1 个答案:

答案 0 :(得分:2)

我们遇到了类似的问题,结果与客户端与服务器的时间戳有关。

通过以这种方式检查请求是否在允许的时间内来解决它(服务器端):

(a > b ? a-b : b-a) > maxtime vs a - b > maxtime

如果b> a,作为无符号长整数(ulong),该值变为巨大值,从而触发无效请求条件。

1522896501 - 1522896502&gt; 300(18446744073709551615是计算的)