【问题标题】:Access Denied - S3 resource using Pre Signed URL - PHP SDK拒绝访问 - 使用预签名 URL 的 S3 资源 - PHP SDK
【发布时间】:2017-04-11 08:34:42
【问题描述】:

我正在生成一个预签名 URL,以允许用户从 S3 存储桶下载文件。我使用以下代码通过 PHP SDK 生成 URL:

public static function get_content_link( $bucket, $key ) {

    //check response code from AWS
    require_once 'aws/aws-autoloader.php';

    $s3 = new Aws\S3\S3Client([
        'version' => 'latest',
        'region'  => 'eu-west-1',
        'credentials' => [
            'key'    => 'MY-KEY',
            'secret' => 'MY-SECRET',
        ],
    ]);

    $cmd = $s3->getCommand('GetObject', [
        'Bucket' => $bucket,
        'Key'    => $key
    ]);

    $request = $s3->createPresignedRequest($cmd, '+500 minutes');

    // Get the actual presigned-url
    $presignedUrl = (string) $request->getUri();

    return $presignedUrl;
}

URL 按预期返回,例如:

https://s3-eu-west-1.amazonaws.com/MY-BUCKET-NAME/product/3166_1480009917388.mov?x-amz-content-sha256=unsigned-payload&x-amz-algorithm=aws4-hmac-sha256&x-amz-credential=akiaiqrmkn276hcpjkaq%2f20161127%2feu-west-1%2fs3%2faws4_request&x-amz-date=20161127t145603z&x-amz-signedheaders=host&x-amz-expires=30000&x-amz-signature=98eaef504f053ca56908ac49c6539c4a8b8e250d7d3a4a12460f4a806ec41c19

当我尝试在浏览器中打开任何返回的链接时,我收到来自 S3 的拒绝访问错误:

<Error>
  <Code>AccessDenied</Code>
  <Message>Access Denied</Message>
  <RequestId>A37839BB23186F72</RequestId>
  <HostId>
yvKTN+CN1TTNk2tqoxxm3MPOGTUSMaRYtbbEFeCzGP7ou5IYf37Z9uBESwUQWDIUR1GUuPbZyuM=
  </HostId>
</Error>

我想要提供访问权限的文件位于包含允许公共访问的文件夹的存储桶中,而我尝试访问的文件夹是私有的(称为 /product/)。我们的存储桶策略如下所示:

{
        "Version": "2008-10-17",
        "Statement": [
            {
                "Sid": "AllowPublicReadProxies",
                "Effect": "Allow",
                "Principal": {
                    "AWS": "*"
                },
                "Action": "s3:GetObject",
                "Resource": "arn:aws:s3:::MY-BUCKET-NAME/proxies*"
            },
            {
                "Sid": "AllowPublicReadThumbs",
                "Effect": "Allow",
                "Principal": {
                    "AWS": "*"
                },
                "Action": "s3:GetObject",
                "Resource": "arn:aws:s3:::MY-BUCKET-NAME/thumbs*"
            }
        ]
    }

据我了解,创建预签名 URL 的目的是允许未经身份验证的用户临时访问受保护的文件,而无需修改存储桶或文件夹权限。

有没有人知道我错过了什么或做错了什么?

谢谢!

【问题讨论】:

  • 您在哪里授予与此 AWS 访问密钥 ID 关联的 IAM 用户执行s3:GetObject 的必要权限?
  • 您可以尝试使用AWS Command-Line Interface (CLI) 生成预签名的 URL,以确认权限有效吗?要使用的命令是aws s3 presign。然后,比较 URL 以确保所有元素都匹配(但值会有所不同)。您提供的 URL 中的“过期”时间似乎不正确。预签名 URL 不依赖存储桶策略 - 它是提供访问权限的另一种方式。
  • @Michael-sqlbot - 我使用的是根访问密钥而不是特定的 IAM 用户。
  • 等一下,@JohnRotenstein,“预签名 URL 不依赖存储桶策略——它是提供访问权限的另一种方式。”需要明确的是,它们不需要存储桶策略,但它们仍然服从存储桶策略(例如拒绝访问或授予拥有键)。
  • 等一下...如何将整个查询字符串强制转换为小写?那肯定是无效的。我可以通过将有效的、有效的签名 URL 转换为全小写来复制这一点。

标签: php amazon-web-services amazon-s3 permissions sdk


【解决方案1】:

如果您收到此错误,还请确保您没有对预签名的 url 发出 GET 请求,而不是 POST 请求。

【讨论】:

    【解决方案2】:

    非常感谢@Michael-sqlbot 帮我解决了这个问题。

    事实证明,在将预签名 URL 输出到页面时,我强制整个 URL 为小写,因此 AWS 返回了拒绝访问错误,因为该资源在技术上不存在。

    【讨论】:

    • 好吧,从技术上讲,访问被拒绝错误是由 S3 忽略小写的 x-amz-* 查询字符串参数引起的,并得出结论,您实际上没有提供任何应该尝试验证的凭据。您基本上可以通过将其中的 just one 更改为全部小写来证明这一点。 S3 会突然抱怨一条新的错误消息,告诉您它丢失了。将它们全部更改为更低,该消息就会消失,因为 S3 假定它是一个匿名请求,没有提供凭据。
    • 是的,我认为这里的常见问题是 url 格式或编码。我遇到了类似的问题,但不是小写,而是由于我使用 curl 导致 url 格式丢失,但没有在 url 字符串周围加上引号
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-21
    • 2018-07-20
    • 2019-09-28
    • 2022-01-28
    • 1970-01-01
    • 2021-12-11
    相关资源
    最近更新 更多