【问题标题】:AWS API GET Request getting response "SignatureDoesNotMatch"AWS API GET 请求获得响应“SignatureDoesNotMatch”
【发布时间】:2016-06-21 15:40:19
【问题描述】:

我正在编写一个 AWS API 请求以列出 IAM AWS 服务上的用户。我收到错误消息。

<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
  <Error>
    <Type>Sender</Type>
    <Code>SignatureDoesNotMatch</Code>
    <Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.

The Canonical String for this request should have been
    'GET
    /
    Action=ListUsers&amp;Version=2010-05-08&amp;X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;X-Amz-Credential=AKIAIMPILWMPQSH57DNA%2F20160621%2Fus-east-1%2Fiam%2Faws4_request&amp;X-Amz-Date=20160621T142939Z&amp;X-Amz-SignedHeaders=host
    host:iam.amazonaws.com

    host
    e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'

The String-to-Sign should have been
    'AWS4-HMAC-SHA256
    20160621T142939Z
    20160621/us-east-1/iam/aws4_request
    c47728e278701ccaada8df76488c18449ada2f1b8aab6275a4bc0ada94af3ce2'
      </Message>
    </Error>
  <RequestId>9672bcf2-37bc-11e6-8b2d-6151d0618c53</RequestId>
</ErrorResponse>

从我下面的代码中可以看出,我的规范字符串与他们在错误响应中写的完全相同,但由于某种原因,当我计算哈希时,我的十六进制值与他们写的不同。 例如,在这个错误响应中,他们写道,十六进制值应该是

`c47728e278701ccaada8df76488c18449ada2f1b8aab6275a4bc0ada94af3ce2` 

当我使用函数时 $hashedcanon = hash_hmac("sha256", $canonicalrequest, True);在我的代码中我得到了

`57fce72007b43c2621712b85e90fd38f0a1f2c7a3e84799fb9f477ed8546f86e`

这是我的代码。

<?php
$AWSAccessKeyId = "<myaccesskey>";
$SecretAccessKey = "<mysecretkey>";
$timestamp = date('Ymd',time()).'T'.date('His',time()).'Z';
$date = date('Ymd',time());
$url = 'https://iam.amazonaws.com';
$method = 'GET';                             
$postfields['Action'] = 'ListUsers';
$postfields['Version'] = '2010-05-08';
$postfields["X-Amz-Algorithm"] = 'AWS4-HMAC-SHA256';
$postfields['X-Amz-Credential'] = $AWSAccessKeyId.'/'.$date.'/us-east-1/iam/aws4_request';
$postfields['X-Amz-Date'] = $timestamp;
$postfields['X-Amz-SignedHeaders'] = 'host';

$canonicalized_query = array();
foreach ($postfields as $param => $value) {
    $param = str_replace("%7E", "~", rawurlencode($param));
    $value = str_replace("%7E", "~", rawurlencode($value));
    $canonicalized_query[] = $param . "=" . $value;
}
$canonicalized_query = implode("&", $canonicalized_query);

$canonicalrequest = $method."\n".
                "/\n".
                $canonicalized_query."\n".                    
                "host:iam.amazonaws.com\n".                    
                "\n".
                "host\n".
                "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";

$hashedcanon = hash_hmac("sha256", $canonicalrequest, True);

$string_to_sign = $postfields["X-Amz-Algorithm"]."\n".$timestamp."\n".$date."/us-east-1/iam/aws4_request\n".$hashedcanon;

$signingkey = hash_hmac("sha256",hash_hmac("sha256",hash_hmac("sha256",hash_hmac("sha256","AWS4".$SecretAccessKey,$date),"us-east-1"),"iam"),"aws4_request");

$signature = hash_hmac("sha256", $string_to_sign, $signingkey, True);

$postfields["X-Amz-Signature"] = $signature;              

$canonicalized_query = array();
foreach ($postfields as $param => $value) {
    $param = str_replace("%7E", "~", rawurlencode($param));
    $value = str_replace("%7E", "~", rawurlencode($value));
    $canonicalized_query[] = $param . "=" . $value;
}
$canonicalized_query = implode("&", $canonicalized_query);

$fullurl = $url.'/?'.$canonicalized_query;

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $fullurl);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLINFO_HEADER_OUT, true); // enable tracking
$result = curl_exec($ch);      
$headerSent = curl_getinfo($ch, CURLINFO_HEADER_OUT );

?>`

所以总的来说,我假设我正在计算要签名的字符串的错误十六进制值,因为我和他们的规范字符串的十六进制值不相同。

当我将我的规范字符串复制/粘贴到http://hash.online-convert.com/sha256-generator 时也很有趣,我得到了第三个十六进制值(甚至不是我的或他们的)。

如果有人需要更多信息,我愿意提供,或者如果有人有任何 API AWS 的工作代码,如果它可以共享,那么我会关注并比较并希望我能找到错误。 谢谢

【问题讨论】:

标签: php api rest amazon-web-services get


【解决方案1】:
$hashedcanon = hash_hmac("sha256", $canonicalrequest, True);

嗯,三个问题...

  • hash_hmac() 将键作为第三个参数,而不是布尔值,并且

  • 你不应该在这里计算 HMAC 摘要,所以hash_hmac() 不是你想要的,并且

  • 你希望它是十六进制的,而不是二进制的,所以不要传递True

您正在寻找的只是hash()

$hashedcanon = hash("sha256", $canonicalrequest);

注意,我并不是说其他​​地方不需要 hash_hmac() —— 只是不在这条线上。

【讨论】:

  • 谢谢迈克尔,你是对的。这是我遇到的问题之一。我修复了您告诉我的内容,规范哈希已修复,但签名错误仍然存​​在。然后我打开 SDK 文件并查看他们的代码,它们是如何散列签名的,它是如何工作的。如果有人需要,我会根据您的回答发布我的工作代码,仅供其他人使用。
【解决方案2】:

大家好,如果其他人需要,我现在将发布已修复且有效的代码。

<?php

$AWSAccessKeyId = "<my access key>";
$SecretAccessKey = "<my secret key>";
$timestamp = date('Ymd',time()).'T'.date('His',time()).'Z';
$date =  date('Ymd',time());
$url = 'https://iam.amazonaws.com';
$method = 'GET';

$postfields['Action'] = 'ListUsers';
$postfields['Version'] = '2010-05-08';
$postfields["X-Amz-Algorithm"] = 'AWS4-HMAC-SHA256';
$postfields['X-Amz-Credential'] = $AWSAccessKeyId.'/'.$date.'/us-east-1/iam/aws4_request';
$postfields['X-Amz-Date'] = $timestamp;
$postfields['X-Amz-SignedHeaders'] = 'host';

$canonicalized_query = array();
foreach ($postfields as $param => $value) {
    $param = str_replace("%7E", "~", rawurlencode($param));
    $value = str_replace("%7E", "~", rawurlencode($value));
    $canonicalized_query[] = $param . "=" . $value;
}
$canonicalized_query = implode("&", $canonicalized_query);

$canonicalrequest = $method."\n".
                    "/\n".
                    $canonicalized_query."\n".                    
                    "host:iam.amazonaws.com\n".                    
                    "\n".
                    "host\n".
                    "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";

$hasedcanon = hash("sha256",$canonicalrequest, false);                  
$credentialScope =  $date."/us-east-1/iam/aws4_request";
$string_to_sign = "AWS4-HMAC-SHA256\n{$timestamp}\n{$credentialScope}\n{$hasedcanon}";

$dateKey = hash_hmac('sha256',$date,"AWS4{$SecretAccessKey}",true);
$regionKey = hash_hmac('sha256', "us-east-1", $dateKey, true);
$serviceKey = hash_hmac('sha256', "iam", $regionKey, true);
$key = hash_hmac('sha256','aws4_request',$serviceKey,true);

$signature = hash_hmac('sha256', $string_to_sign, $key);

$postfields["X-Amz-Signature"] = $signature;              

$canonicalized_query = array();
foreach ($postfields as $param => $value) {
    $param = str_replace("%7E", "~", rawurlencode($param));
    $value = str_replace("%7E", "~", rawurlencode($value));
    $canonicalized_query[] = $param . "=" . $value;
}
$canonicalized_query = implode("&", $canonicalized_query);

$fullurl = $url.'/?'.$canonicalized_query;

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $fullurl);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLINFO_HEADER_OUT, true); // enable tracking
$xml = curl_exec($ch);      
$headerSent = curl_getinfo($ch, CURLINFO_HEADER_OUT );      

$doc = simplexml_load_string($xml);
echo '<pre>';
print_r($doc);
echo '</pre>';

?>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-02
    • 1970-01-01
    • 2014-09-01
    • 1970-01-01
    • 2017-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多