AWS S3 存储桶预签名 URL

Posted

技术标签:

【中文标题】AWS S3 存储桶预签名 URL【英文标题】:AWS S3 Bucket Presigned URL 【发布时间】:2019-01-27 08:22:04 【问题描述】:

我正在尝试为用户创建预签名 URL 以访问 S3 存储桶中的内容。

以下代码运行良好,但在打开任何已创建的预签名 URL 时突然出现以下错误。

public function getPresignedUri($p)

    $s3 = new S3Client([
        'region'  => getenv('S3_REGION'),
        'version' => 'latest',
    ]);

    $cmd = $s3->getCommand('GetObject', [
      'Bucket' => getenv('S3_BUCKET'),
      'Key'    => 'casts/'. $p['file']
    ]);

    $request = $s3->createPresignedRequest($cmd, '+1 hour');

    return (string) $request->getUri();

<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>ASIA3DM6Y5GJC4FYJAFC</AWSAccessKeyId><StringToSign>AWS4-HMAC-SHA256
20180821T072223Z
20180821/ap-southeast-2/s3/aws4_request
fc4f1139d3b146ae027bd0bfc0b3d6dacda81d711b062e0d93a65d04a61aa268</StringToSign><SignatureProvided>5f5d3ae9ef3d9cdfc0d039c39302c584dcfc93f5a94a0f1770bf6781d6958198</SignatureProvided><StringToSignBytes>41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 0a 32 30 31 38 30 38 32 31 54 30 37 32 32 32 33 5a 0a 32 30 31 38 30 38 32 31 2f 61 70 2d 73 6f 75 74 68 65 61 73 74 2d 32 2f 73 33 2f 61 77 73 34 5f 72 65 71 75 65 73 74 0a 66 63 34 66 31 31 33 39 64 33 62 31 34 36 61 65 30 32 37 62 64 30 62 66 63 30 62 33 64 36 64 61 63 64 61 38 31 64 37 31 31 62 30 36 32 65 30 64 39 33 61 36 35 64 30 34 61 36 31 61 61 32 36 38</StringToSignBytes><CanonicalRequest>GET
/casts/5B735D22BCB17.mp4
X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIA3DM6Y5GJC4FYJAFC%2F20180821%2Fap-southeast-2%2Fs3%2Faws4_request&X-Amz-Date=20180821T072223Z&X-Amz-Expires=3600&X-Amz-Security-Token=FQoGZXIvYXdzEPn%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaDEMaw7h8OwK6f6QN0SLBA4%2B9LzXs7OMNjW7HDqr1jhuK%2FshbOMDBoF00GHqTWUuJWXQuL4ptYpvWRjwpris0USWPMTx0O3WeKacvtw6oN2M1KRoUe3IcNOpFwaixKw8%2Fo5FKXK%2BSCo%2F7U%2B76V4aEFuuWEZkC5qhm9R7ChB7vDNTlmYXx2GOzL2uZYV8dZrAnrUfU5qWpyI4IQb8D***pDWB0OgA2SRvuGzkwkVLEtMmHS2SMU32gwX2Oy6YnMswWZeqVQ%2FovfWbxd5AA4O%2BFNQfcNM5l4jsuR2zV8FiKZ3jQRLgfQx5uvydv6FFzb90SDbvUjZd0aAsR1Mre%2FnoQodezAm0xoA5618%2FWd%2BIh3jouN2RflRM3II8UXCWzFFq2NL%2FxweJu2mYXfKNpTkqOEls5dFMo2OWQa3IGXJqT3EZEZKXcQ3z%2F2aOP%2Fyw%2F2GtPdQrdJziwN4lTXyl6%2FGZYd968yjlU6pIk6vB0NVq9q3wKjBiwlsfGTlaJnFJH7DD%2FIY4U6fYOmvAcGnoozAbIcqDZpDPNrvZX75tzSatHHLyQoF56STZPhWK7cCWEo2JWAzg6NE4xBmypFG%2Bkxtv0QtrcUNYD35FvFGbjheUhMnyOKOTz7tsF&X-Amz-SignedHeaders=host
host:app-assets-dev-ap-southeast-2-cmpny.s3.ap-southeast-2.amazonaws.com
 
host
UNSIGNED-PAYLOAD</CanonicalRequest>

AWS 开发工具包版本 aws/aws-sdk-php (3.65.0)

我可以在 URL 中看到的一个小区别是它在工作时有

X-Amz-SignedHeaders=主机

现在有了

X-Amz-SignedHeaders=host%3Bx-amz-security-token

虽然不确定是什么导致了额外的字符串?

编辑 1:

我发现这个问题是由于 SDK 版本 3.65 造成的……当我回滚到 3.31 时没有问题。

但是我并没有将此标记为已解决,因为我想知道为什么像这样的小版本更改会产生如此大的差异和错误?

我可以看到 src/Signature/SignatureS4.php 文件有很大的不同:

$parsed['query']['X-Amz-SignedHeaders'] = 'host'; (V3.31)

$parsed['query']['X-Amz-SignedHeaders'] = implode(';', $this->getPresignHeaders($parsed['headers'])); (V3.65)

然而,仅此行并没有修复 - 替换整个文件确实修复了错误。

【问题讨论】:

提出的问题:github.com/aws/aws-sdk-php/issues/1609 【参考方案1】:

我在 Github 上记录了这个问题 - https://github.com/aws/aws-sdk-php/issues/1609

而且很快就得到了测试、确认和解决 - https://github.com/aws/aws-sdk-php/pull/1610

已解决。

【讨论】:

我会请求您在 48 小时等待时间过去后接受此作为解决方案,因此将其标记为已解决。谢谢! :)

以上是关于AWS S3 存储桶预签名 URL的主要内容,如果未能解决你的问题,请参考以下文章

如何使用预签名的 url 将对象放入 amazon s3?

使用预签名 URL 上传到 S3 存储桶会出现 403 禁止错误

AWS 静态网站 + 云端签名 cookie

AWS CloudFront 签名 URL 的访问被拒绝

使用其预签名 URL 从 AWS s3 读取文件的内容

仅从浏览器使用预签名 URL 上传时出现 AWS S3 CORS 错误