Amazon API генерирует подпись запроса в C# .NET

Я пытаюсь выяснить, как передать параметр в моем приложении.NET. 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]

Часть, в которой я запутался, это:

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

Я не уверен, смогу ли я просто сделать что-то вроде этого для отметки времени:

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

Поэтому мой вопрос заключается в том, как на самом деле создать этот URL-адрес подписи в URL-адресе запроса?

У меня есть все эти параметры выше, но я не уверен, как сгенерировать этот последний?

Кто-нибудь может мне помочь?

1 ответ

Решение

AWS использует HMAC-запрос подписи. Вообще говоря, способ, которым это работает, заключается в том, что вы создаете "сообщение", которое состоит из таких вещей, как ваш ключ (ы) доступа, заголовки запроса, тело запроса и временная метка. Затем вы HMAC это "сообщение", и это становится вашей "подписью" для запроса. Это предотвращает повторные атаки, поскольку каждый запрос должен иметь уникальную подпись.

Похоже, что отметка времени просто должна быть в формате ISO (YYYY-MM-DDThh:mm:ssZ), так что нет, вы не можете просто использовать DateTime.Now, Формат по умолчанию, используемый ToString не будет ISO. Вместо этого вам нужно использовать что-то вроде:

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

Или, возможно, было бы лучше использовать время UTC и просто добавить Z:

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

Что касается создания подписи, см. Документацию 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));
}

Вопреки большинству ответов, найденных здесь и в других местах, это единственный способ, который работает. Весь запрос должен быть хэширован, а не только конкретные параметры. Я не могу разговаривать с другими сервисами Amazon, но Commerce Service должен быть сделан следующим образом.

Несколько ответов здесь и в других местах ссылались на это: https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html Это, безусловно, не правильно. Если вы не передаете параметр региона, как Amazon может создать такую ​​же подпись, поскольку она не имеет всей информации.

Другие вопросы по тегам