使用PHP创建AWS签名


AWS Signature creation using PHP

我正试图使用AWS API在AWS CloudFormation中创建堆栈,但他们返回错误,称"我们计算的签名与您提供的签名不匹配"

Fllowing是我用来生成信号的代码

$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'

这是您的代码,稍微整理了一下,其中有一个示例函数显示了如何将这种方法扩展到其他AWS API。

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
    ));
}

这对我有用。

$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 Id没有为产品广告API注册。请使用在注册后获得的AccessKey Idhttps://affiliate-program.amazon.com/assoc_credentials/home

转到https://affiliate-program.amazon.com/assoc_credentials/home

您也可以在以下位置模拟您的查询:

https://webservices.amazon.com/scratchpad/index.html然后点击项目搜索。

我确认了弗雷德里克的回答。在对数组进行哈希之前,必须对其进行k排序。

您为什么不使用AWS SDK for PHP?它为您处理所有这些。