【问题标题】:Amazon ElasticSearch service Signature mismatch for PUT Request - Amazon SDK php V2PUT 请求的 Amazon ElasticSearch 服务签名不匹配 - Amazon SDK php V2
【发布时间】:2017-10-10 08:46:56
【问题描述】:

我正在使用 Amazon ElasticSearch 服务,当我尝试创建 SignatureV4 请求时,它对于搜索操作(GET 请求)运行良好。但是当我尝试执行一些操作,如创建索引(使用 PUT 请求)时,它会出现签名不匹配错误。

我正在使用 Amazon SDK 版本 2 SignatureV4 库对请求进行签名。还创建了一个自定义 Elasticsearch 处理程序来向请求添加令牌。

有人对 Amazon SDK php V2 中的 SignatureV4 库有这样的问题吗?

{"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.\n\nThe Canonical String for this request should have been\n'PUT\n/test_index_2\n\nhost:search-test-gps2gj4zx654muo6a5m3vxm3cy.eu-west-1.es.amazonaws.com\nx-amz-date:XXXXXXXXXXXX\n\nhost;x-amz-date\n271d5ef919251148dc0b5b3f3968c3debc911a41b60ef4e92c55b98057d6cdd4'\n\nThe String-to-Sign should have been\n'AWS4-HMAC-SHA256\XXXXXXXXXXXX\n20170511/eu-west-1/es/aws4_request\n0bd34812e0727fba7c54068b0ae1114db235cfc2f97059b88be43e8b264e1d57'\n"}

【问题讨论】:

  • 是的@VladHolubiev 我尝试了他们记录的相同方式,它适用于 GET 操作,如(搜索、查找项目等)。但不适用于 PUT 操作。
  • 如果它适用于一个而不适用于另一个,那么请求中存在使您的逻辑无效的细微差别。错误消息为您提供了一些有价值的故障排除信息,包括规范请求(以 sha256hex 有效负载哈希结尾)和字符串签名(以规范请求的 sha256hex 哈希结尾)。找到您的签名过程中产生错误结果的步骤,并解决在该步骤中出现的问题。它只能在那里,而不是以后,因为任何步骤的错误结果总会级联出来。
  • @Michael-sqlbot 问题在于 PUT 请求,有效载荷哈希没有考虑请求正文。这导致无效的签名。感谢您的帮助。
  • 就可以了。我很高兴你找到了。您认为这里有机会通过发布有用/有意义的答案/解决方案来帮助未来的访问者吗?例如,如果可以显示错误页面以及您如何使用该信息来逐步完成故障排除过程...或者您在文档中发现一些模棱两可的内容导致您出现编码错误...或者我们应该关闭它作为一个无法再重现的问题?还是要删除问题?

标签: php amazon-web-services elasticsearch amazon-elasticsearch


【解决方案1】:

此调整仅适用于仍在使用 Amazon SDK PHP 版本 2 的用户。在版本 3 中,默认支持。

对于已签名的请求,我通过添加用于签署请求的中间件来更新当前的 elsticsearch 客户端处理程序。

$elasticConfig = Configure::read('ElasticSearch');
$middleware = new AwsSignatureMiddleware();
$defaultHandler = \Elasticsearch\ClientBuilder::defaultHandler();
$awsHandler = $middleware($defaultHandler);

$clientBuilder =  \Elasticsearch\ClientBuilder::create();
$clientBuilder->setHandler($awsHandler)
            ->setHosts([$elasticConfig['host'].':'.$elasticConfig['port']]);
$client = $clientBuilder->build();

我为此使用了以下库

use Aws\Common\Credentials\CredentialsInterface;
use Aws\Common\Signature\SignatureInterface;
use Guzzle\Http\Message\Request;

class AwsSignatureMiddleware
{
/**
 * @var \Aws\Credentials\CredentialsInterface
 */
protected $credentials;

/**
 * @var \Aws\Signature\SignatureInterface
 */
protected $signature;

/**
 * @param CredentialsInterface $credentials
 * @param SignatureInterface $signature
 */
public function __construct()
{
    $amazonConf = Configure::read('AmazonSDK');
    $this->credentials = new \Aws\Common\Credentials\Credentials($amazonConf['key'], $amazonConf['secret']);
    $this->signature = new \Aws\Common\Signature\SignatureV4('es', 'eu-west-1');
}

/**
 * @param $handler
 * @return callable
 */
public function __invoke($handler)
{
    return function ($request)  use ($handler) {
        $headers = $request['headers'];
        if ($headers['host']) {
            if (is_array($headers['host'])) {
                $headers['host'] = array_map([$this, 'removePort'], $headers['host']);
            } else {
                $headers['host'] = $this->removePort($headers['host']);
            }
        }
        if (!empty($request['body'])) {
            $headers['x-amz-content-sha256'] = hash('sha256', $request['body']);
        }

        $psrRequest = new Request($request['http_method'], $request['uri'], $headers);
        $this->signature->signRequest($psrRequest, $this->credentials);
        $headerObj = $psrRequest->getHeaders();
        $allHeaders = $headerObj->getAll();

        $signedHeaders = array();
        foreach ($allHeaders as $header => $allHeader) {
            $signedHeaders[$header] = $allHeader->toArray();
        }
        $request['headers'] = array_merge($signedHeaders, $request['headers']);
        return $handler($request);
    };
}

protected function removePort($host)
{
    return parse_url($host)['host'];
}
}

我为此目的调整的确切行是

if (!empty($request['body'])) {
    $headers['x-amz-content-sha256'] = hash('sha256', $request['body']);
}

对于 PUT 和 POST 请求,有效负载哈希是错误的,因为我在生成有效负载时没有考虑请求正文。

希望此代码对使用 Amazon SDK PHP 版本 2 并在 Amazon 云中使用基于 IAM 的 Elasticsearch 托管服务的身份验证的任何人都有益。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-11
    • 1970-01-01
    • 2017-08-26
    • 1970-01-01
    • 2015-08-11
    • 1970-01-01
    相关资源
    最近更新 更多