简体   繁体   English

Amazon API在C#.NET中生成请求签名

[英]Amazon API generating a request signature in C# .NET

I'm trying to figure out how to pass a parameter in my .NET application. 我试图弄清楚如何在.NET应用程序中传递参数。 The URL request looks like: URL请求如下所示:

http://webservices.amazon.com/onca/xml?
  Service=AWSECommerceService
  &Operation=ItemLookup
  &ResponseGroup=Large
  &SearchIndex=All
  &IdType=UPC
  &ItemId=635753490879
  &AWSAccessKeyId=[Your_AWSAccessKeyID]
  &AssociateTag=[Your_AssociateTag]
  &Timestamp=[YYYY-MM-DDThh:mm:ssZ]
  &Signature=[Request_Signature]

The part that I'm confused about are these: 我感到困惑的部分是:

 &Timestamp=[YYYY-MM-DDThh:mm:ssZ]
      &Signature=[Request_Signature]

I'm not sure whether I can Just simply do it something like this for timestamp part: 我不确定是否可以在时间戳部分简单地执行以下操作:

var TimeStamp  = DateTime.Now; // without any special datetime formating? 

So my question is how do I actually generate this signature URL in the request URL ? 所以我的问题是我该如何在请求URL中实际生成此签名URL?

I have all of these parameters above but I'm not sure how to generate this last one ? 我上面有所有这些参数,但是我不确定如何生成最后一个?

Can someone help me out ? 有人可以帮我吗 ?

AWS utilizes HMAC request-signing. AWS利用HMAC请求签名。 Generally speaking, the way this works is that you create a "message", which is composed of things like your access key(s), request headers, request body and a timestamp. 一般而言,此方法的工作方式是创建一个“消息”,该消息由诸如访问密钥,请求标头,请求正文和时间戳之类的内容组成。 You then HMAC this "message" and that becomes your "signature" for the request. 然后,您向HMAC发送此“消息”,并成为请求的“签名”。 This prevents replay-attacks as each request must have a unique signature. 这可以防止重播攻击,因为每个请求必须具有唯一的签名。

It looks like the timestamp simply needs to be in ISO format ( YYYY-MM-DDThh:mm:ssZ ), so, no you can't just use DateTime.Now . 看起来时间戳仅需要采用ISO格式( YYYY-MM-DDThh:mm:ssZ ),所以,不,您不能仅使用DateTime.Now The default format utilized by ToString will not be ISO. ToString使用的默认格式将不是ISO。 Instead, you'd need to use something like: 相反,您需要使用以下方法:

DateTime.Now.ToString("yyyy-MM-ddThh:mm:sszzz");

Or it would actually probably be better to use UTC time and simply append a Z : 或者,实际上最好使用UTC时间并简单地附加一个Z

DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ssZ");

As for creating the signature, see the AWS documentation , where they provide some sample code: 至于创建签名,请参阅AWS文档 ,其中提供了一些示例代码:

static byte[] HmacSHA256(String data, byte[] key)
{
    String algorithm = "HmacSHA256";
    KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(algorithm);
    kha.Key = key;

    return kha.ComputeHash(Encoding.UTF8.GetBytes(data));
}

static byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName)
{
    byte[] kSecret = Encoding.UTF8.GetBytes(("AWS4" + key).ToCharArray());
    byte[] kDate = HmacSHA256(dateStamp, kSecret);
    byte[] kRegion = HmacSHA256(regionName, kDate);
    byte[] kService = HmacSHA256(serviceName, kRegion);
    byte[] kSigning = HmacSHA256("aws4_request", kService);

    return kSigning;
}
/*

    DOCUMENTATION: https://docs.aws.amazon.com/AWSECommerceService/latest/DG/rest-signature.html#rest_detailedexample
*/

    var itemID = "0679722769";
    var accessKeyID = "AKIAIOSFODNN7EXAMPLE";
    var timeStamp = DateTime.UtcNow.ToString("o");
    var req = $"Service=AWSECommerceService&AWSAccessKeyId={accessKeyID}&Operation=ItemLookup&IdType=UPC&ItemId={itemID}&Version=2013-08-01&Timestamp={timeStamp}";
    req = req.Replace(":", "%3A").Replace(",", "%2C"); //UrlDecode certain characters
    var reqlist = req.Split('&').ToArray(); //we need to sort our key/value pairs
    Array.Sort(reqlist);
    req = String.Join("&", reqlist); //join everything back
    var reqToSign = $@"GET
webservices.amazon.com
/onca/xml
{req}".Replace("\r", ""); //create the request for signing. We need to replace microsofts's crlf with just a lf; Make sure there are no leading spaces after the linefeeds.

    var signage = getSignatureKey("1234567890",reqToSign);
    req = $"http://webservices.amazon.com/onca/xml?{req}&Signature={signage}"; //create our request with the signature appended.
    return req;
}

private static byte[] HmacSHA256(String data, byte[] key)
{
    String algorithm = "HmacSHA256";
    KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(algorithm);
    kha.Key = key;

    return kha.ComputeHash(Encoding.UTF8.GetBytes(data));
}


private static string getSignatureKey(string key, string stringToSign)
{
    byte[] kSecret = Encoding.UTF8.GetBytes(key.ToCharArray());
    byte[] kSigning = HmacSHA256(stringToSign, kSecret);
    return WebUtility.UrlEncode(Convert.ToBase64String(kSigning));
}

Contrary to most of the answers found here and elsewhere, this is the only way that works. 与这里和其他地方的大多数答案相反,这是唯一有效的方法。 The entire request has to be hashed, not just particular parameters. 必须对整个请求进行哈希处理,而不仅仅是特定的参数。 I can't speak to other Amazon services, but the Commerce Service has to be done like this. 我无法与其他Amazon服务交谈,但是必须像这样完成Commerce Service。

Quite a few answers here and elsewhere referenced this: https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html This is most certainly not correct. 这里和其他地方都引用了很多答案: https : //docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html这肯定是不正确的。 If you're not passing a region parameter, how can Amazon create the same signature since it doesn't have all the information. 如果您没有传递region参数,那么Amazon如何创建相同的签名,因为它没有所有信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM