Создание подписи AWS с помощью PHP

Я пытаюсь использовать AWS API для создания стека в AWS CloudFormation, но они возвращают сообщение об ошибке «рассчитанная нами подпись не соответствует предоставленной вами подписи»

Flowing — это код, который я использую для создания подписи.

$private_key = "xxxxxxxxxxxxx";
$params = array();
$method = "POST";
$host = "cloudformation.eu-west-1.amazonaws.com";
$uri = "/onca/xml";

// additional parameters
$params["Service"] = "AWSCloudFormation";
$params["Operation"] = "DeleteStack";
$params["AWSAccessKeyId"] = "xxxxxxxxxxxxxx";
// GMT timestamp
$params["Timestamp"] = gmdate("Y-m-d\TH:i:s\Z");
// API version
$params["Version"] = "2010-05-15";

// sort the parameters
// create the canonicalized query
$canonicalized_query = array();
foreach ($params as $param => $value) {
    $param = str_replace("%7E", "~", rawurlencode($param));
    $value = str_replace("%7E", "~", rawurlencode($value));
    $canonicalized_query[] = $param . "=" . $value;
}
$canonicalized_query = implode("&", $canonicalized_query);

// create the string to sign
$string_to_sign = $method . "\n" . $host . "\n" . $uri . "\n" . $canonicalized_query;

// calculate HMAC with SHA256 and base64-encoding
$signature = base64_encode(hash_hmac("sha256", $string_to_sign, $private_key, True));

// encode the signature for the request
$signature = str_replace("%7E", "~", rawurlencode($signature));

the url I am using is 

'https://cloudformation.us-east-1.amazonaws.com/
?Action=DeleteStack
&StackName=MyStack
&Version=2010-05-15
&SignatureVersion=2
&Timestamp=2012-09-05T06:32:19Z
&AWSAccessKeyId=[AccessKeyId]
&Signature=[Signature]
&SignatureMethod=HmacSHA256'

person Reneshankar    schedule 05.09.2012    source источник
comment
это не похоже на то, что вы сортируете свои параметры перед формированием канонизированной строки запроса.   -  person Frederick Cheung    schedule 05.09.2012


Ответы (4)


Я подтвердил ответ Фредерика. Вы должны отсортировать массив перед его хешированием.

person Community    schedule 20.09.2012
comment
uksort($params, 'strcmp'); точнее :) - person Thomas Smart; 23.10.2013

Вот ваш код, немного подправленный, с примером функции, показывающей, как распространить этот подход на другие API AWS.

function aws_query($extraparams) {
    $private_key = ACCESS_SECRET_KEY;

    $method = "GET";
    $host = "webservices.amazon.com";
    $uri = "/onca/xml";

    $params = array(
        "AssociateTag" => ASSOCIATE_TAG,
        "Service" => "AWSECommerceService",
        "AWSAccessKeyId" => ACCESS_KEY_ID,
        "Timestamp" => gmdate("Y-m-d\TH:i:s\Z"),
        "SignatureMethod" => "HmacSHA256",
        "SignatureVersion" => "2",
        "Version" => "2013-08-01"
    );

    foreach ($extraparams as $param => $value) {
        $params[$param] = $value;
    }

    ksort($params);

    // sort the parameters
    // create the canonicalized query
    $canonicalized_query = array();
    foreach ($params as $param => $value) {
        $param = str_replace("%7E", "~", rawurlencode($param));
        $value = str_replace("%7E", "~", rawurlencode($value));
        $canonicalized_query[] = $param . "=" . $value;
    }
    $canonicalized_query = implode("&", $canonicalized_query);

    // create the string to sign
    $string_to_sign =
        $method . "\n" .
        $host . "\n" .
        $uri . "\n" .
        $canonicalized_query;

    // calculate HMAC with SHA256 and base64-encoding
    $signature = base64_encode(
        hash_hmac("sha256", $string_to_sign, $private_key, True));

    // encode the signature for the equest
    $signature = str_replace("%7E", "~", rawurlencode($signature));

    // Put the signature into the parameters
    $params["Signature"] = $signature;
    uksort($params, "strnatcasecmp");

    // TODO: the timestamp colons get urlencoded by http_build_query
    //       and then need to be urldecoded to keep AWS happy. Spaces
    //       get reencoded as %20, as the + encoding doesn't work with 
    //       AWS
    $query = urldecode(http_build_query($params));
    $query = str_replace(' ', '%20', $query);

    $string_to_send = "https://" . $host . $uri . "?" . $query;

    return $string_to_send;
}

function aws_itemlookup($itemId) {
    return aws_query(array (
        "Operation" => "ItemLookup",
        "IdType" => "ASIN",
        "ItemId" => $itemId
    ));
}
person Buddy    schedule 25.05.2015

Это сработало для меня.

$str = "Service=AWSECommerceService&Operation=ItemSearch&AWSAccessKeyId={Access Key}&Keywords=Harry%20Potter&ResponseGroup=Images%2CItemAttributes%2COffers&SearchIndex=Books&Timestamp=2019-08-11T17%3A51%3A56.000Z";


$ar = explode("&", $str);

natsort($ar);

$str = "GET
webservices.amazon.com
/onca/xml
";

$str .= implode("&", $ar); 

$str = urlencode(base64_encode(hash_hmac("sha256",$str,'{Secret Key Here}',true)));


http://webservices.amazon.com/onca/xml?Service=AWSECommerceService&Operation=ItemSearch&AWSAccessKeyId={Access Key}&Keywords=Harry%20Potter&ResponseGroup=Images%2CItemAttributes%2COffers&SearchIndex=Books&Timestamp=2019-08-11T17%3A51%3A56.000Z&Signature=$str

Помните: если вы получили эту ошибку, ваш идентификатор AccessKey не зарегистрирован для Product Advertising API. Используйте идентификатор AccessKey, полученный после регистрации на странице https://affiliate-program.amazon.com/assoc_credentials/home

Перейдите на страницу https://affiliate-program.amazon.com/assoc_credentials/home.

Вы также можете смоделировать свой запрос по адресу:

https://webservices.amazon.com/scratchpad/index.html и нажмите поиск предметов.

person rescue1155    schedule 08.05.2019
comment
Спасибо за публикацию. Я много раз гуглил, чтобы найти простой ответ о том, как сгенерировать подпись AWS для API рекламы продуктов, поскольку этого сервиса нет в AWS SDK. Это самый простой ответ, который я видел вместо этого - person De'Yonte W.; 13.09.2019

Есть ли причина, по которой вы не используете только SDK AWS для PHP? Он обрабатывает все это для вас.

person Ryan Parman    schedule 05.10.2012
comment
aws sdk в среднем в 2 раза медленнее, чем прямые запросы на отдых (если все сделано правильно) - person Thomas Smart; 23.10.2013
comment
AWS SDK — огромное чудовище. Если вам не нужны некоторые из его более сложных функций, лучше избегать их для простого использования AWS, особенно если важна скорость. - person orrd; 16.08.2016
comment
@ThomasSmart: я был бы очарован, увидев тесты, выполняющие сопоставимые задачи. Честно. - person Ryan Parman; 16.08.2016
comment
@orrd: Какое значение имеет размер? Это одна строка в вашем файле composer.json. Это было то, с чем я боролся после того, как мы выпустили 1.0. Но чем больше я думал об этом, тем больше понимал, что с Composer это вообще не имеет значения. Разработчики Swift/Obj-C избегают Xcode и фреймворков Apple только потому, что это 8 ГБ? Конечно, нет! Потому что единственный код, который работает, — это код, который вам нужен. - person Ryan Parman; 16.08.2016
comment
@RyanParman Меня беспокоит не размер установки, но на самом деле он запускает тонну PHP-кода даже для простых запросов. Я экспериментировал с ним, и он был медленным и требовательным к памяти, поэтому я решил, что имеет смысл написать простой код запроса с нуля. Но это было много лет назад, когда я в последний раз пробовал это, поэтому, как упомянул Томас Смарт, тесты были бы лучше, чтобы получить справедливое сравнение, так что это всего лишь слухи. - person orrd; 16.08.2016
comment
@RyanParman я представил их группе пользователей AWS в Сингапуре 2 года назад, но вы можете увидеть сводку здесь: cloudcore. облако/контрольные показатели. Фреймворк использует прямые вызовы API с дополнительной обработкой по мере необходимости, и это немного быстрее. Однако эти тесты были проведены 2 года назад и с тех пор не пересматривались. Я также всегда указываю, что цели моего фреймворка и SDK немного отличаются. SDK отлично работает по принципу plug-and-play и работает легко. Framework предназначена для более масштабных проектов, где эффективность запросов может быть более приоритетной. - person Thomas Smart; 17.08.2016
comment
В случае с плагином WordPress размер ZIP-файла должен быть меньше 2 МБ, чтобы пользователи с ограниченным хостингом могли установить его через загрузку. Помимо преимуществ в размере и ресурсах с прямым cURL, библиотеки композитора необходимо конвертировать, когда вы не контролируете среду. Когда мне нужны только S3 и CloudFront, я в конечном итоге трачу время на удаление всего остального, и я все равно не буду знать о каждой строке кода, который я отправляю. - person ljs.dev; 10.01.2019