测试 AWS S3 Presigned Url 返回 403 Forbidden (Nodejs)
Posted
技术标签:
【中文标题】测试 AWS S3 Presigned Url 返回 403 Forbidden (Nodejs)【英文标题】:Testing a AWS S3 Presigned Url returns 403 Forbidden (Nodejs) 【发布时间】:2020-10-05 23:48:50 【问题描述】:我在 API 网关后面有一个 Lambda Nodejs 函数,它成功返回了一个预签名 URL:
const AWS = require('aws-sdk');
const S3 = new AWS.S3(
apiVersion: '2006-03-01',
signatureVersion: 'v4'
);
function getSignedUrl(id, type)
const key = `uploads/$id.$type`;
return S3.getSignedUrl('putObject',
Bucket: 'example-bucket-name',
Key: key,
Expires: 300
);
预签名 URL 可能如下所示:
https://example-bucket-name.s3.eu-central-1.amazonaws.com/uploads/489eb7115d0c479eaf9c3b6a01eb1893.png?Content-Type=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIARTVN4TPKUACY5POZ%2F20200616%2Feu-central-1%2Fs3%2Faws4_request&X-Amz-Date=20200616T104031Z&X-Amz-Expires=300&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEMaDGV1LWNlbnRyYWwtMSJHMEUCIQCDd%2B5hFjcBd%2FA6TEV7Se6L%2B6V8VtgCrMg0%2FbOkoGKy1wIgL20u20i%2B80rnBf49MfU1T3MQK2RQdoyQF6SwGQiYgeMq7gEIvP%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARABGgwxMTA5NjAwOTAwNjkiDIcy2z8%2FpQIhMOOaZirCAUFhV6uGF%2Ff44lDl%2BaFxIt9D302gcuPaxlrgZWlRMHb%2FEdrKFJsWP%2FG7%2B6ovilKh9WmcBX1fzuVa%2BHQ6rv6OaCueMEnDOBEj%2FvJ1hrI%2FwMDF1RLVlqq7pTDp6h6hmUxPfbqXu1k8sjcFotVzXZTzR0dX6kmWl41uEvaglXjrGG3ApvviH%2BSFLdUdvK9PBgrgSlamGIhxdJN75xxBzQMELfdpPJ6QanhLEwIa%2FuMliHPliXC2fasMzFEheA3Xmik43McnMJ3DovcFOuABdae1G7uUXOSaQzGZ7IjPLLZnMFfow4SzosQHlMUurlqQATPbieC9W3McsMVwggwzZX6BcN9OJb%2B0Ag3x9pS5eLnLsEio%2FyAPZJfXzoGBH5AdZ6TAZtC5cgKy0TEebH%2F3bF4%2FiamoTQ6YcZ4f48NefoNFHcRPXl3VF%2FdINmuTSG1cNlh2svT9jAUfOgaeK7tnFAW79L38Nv7xnnFMYFpyxoUx8XVkffCXmq15dyG7rLIR0FHkJ7p4C8eEqbQzOj%2Fsj1ELFFAWPtq38ZgFnWF%2BYf6W4UrkHD9AGdUucD1qvAA%3D&X-Amz-Signature=e11f346296a979e586b8f81a9db2ef2ce58c9f7a13a4f3c31f9a0bb9997b8b81&X-Amz-SignedHeaders=host
但是,在浏览器中测试上述 URL 时,我得到一个 SignatureDoesNotMatch。我想这似乎是公平的,因为我以后只想将它与应用程序中的 PUT 一起使用。
使用 curl 或 postman 我得到 403 Forbidden:
curl -v -X PUT -T 489eb7115d0c479eaf9c3b6a01eb1893.png "https://example-bucket-name.s3.eu-central-1.amazonaws.com/uploads/489eb7115d0c479eaf9c3b6a01eb1893.png?Content-Type=image%2Fpng&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIARTVN4TPKUACY5POZ%2F20200616%2Feu-central-1%2Fs3%2Faws4_request&X-Amz-Date=20200616T104031Z&X-Amz-Expires=300&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEMaDGV1LWNlbnRyYWwtMSJHMEUCIQCDd%2B5hFjcBd%2FA6TEV7Se6L%2B6V8VtgCrMg0%2FbOkoGKy1wIgL20u20i%2B80rnBf49MfU1T3MQK2RQdoyQF6SwGQiYgeMq7gEIvP%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARABGgwxMTA5NjAwOTAwNjkiDIcy2z8%2FpQIhMOOaZirCAUFhV6uGF%2Ff44lDl%2BaFxIt9D302gcuPaxlrgZWlRMHb%2FEdrKFJsWP%2FG7%2B6ovilKh9WmcBX1fzuVa%2BHQ6rv6OaCueMEnDOBEj%2FvJ1hrI%2FwMDF1RLVlqq7pTDp6h6hmUxPfbqXu1k8sjcFotVzXZTzR0dX6kmWl41uEvaglXjrGG3ApvviH%2BSFLdUdvK9PBgrgSlamGIhxdJN75xxBzQMELfdpPJ6QanhLEwIa%2FuMliHPliXC2fasMzFEheA3Xmik43McnMJ3DovcFOuABdae1G7uUXOSaQzGZ7IjPLLZnMFfow4SzosQHlMUurlqQATPbieC9W3McsMVwggwzZX6BcN9OJb%2B0Ag3x9pS5eLnLsEio%2FyAPZJfXzoGBH5AdZ6TAZtC5cgKy0TEebH%2F3bF4%2FiamoTQ6YcZ4f48NefoNFHcRPXl3VF%2FdINmuTSG1cNlh2svT9jAUfOgaeK7tnFAW79L38Nv7xnnFMYFpyxoUx8XVkffCXmq15dyG7rLIR0FHkJ7p4C8eEqbQzOj%2Fsj1ELFFAWPtq38ZgFnWF%2BYf6W4UrkHD9AGdUucD1qvAA%3D&X-Amz-Signature=e11f346296a979e586b8f81a9db2ef2ce58c9f7a13a4f3c31f9a0bb9997b8b81&X-Amz-SignedHeaders=host"
Lambda 函数具有以下权限:
s3:ListBucket Allow: arn:aws:s3:::example-bucket-name
s3:GetBucketLocation Allow: arn:aws:s3:::example-bucket-name
s3:PutObject Allow: arn:aws:s3:::example-bucket-name/uploads/*
S3 存储桶具有以下 CORS 规则:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<ExposeHeader>ETag</ExposeHeader>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
这是存储桶 ACL:
"Version": "2012-10-17",
"Statement": [
"Sid": "AWSConfigBucketPermissionsCheck",
"Effect": "Allow",
"Principal":
"Service": "config.amazonaws.com"
,
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::example-bucket-name"
,
"Sid": "DenyUnEncryptedTraffic",
"Effect": "Deny",
"Principal":
"AWS": "*"
,
"Action": "*",
"Resource": "arn:aws:s3:::example-bucket-name/*",
"Condition":
"Bool":
"aws:SecureTransport": "false"
]
会不会是上面的 DenyUnEncryptedTraffic 规则导致了 403?我通过删除所述规则对其进行了测试,但仍然得到 403。
阻止所有公共访问已开启!
存储桶拥有者拥有存储桶的完全访问权限!
我已经在这方面浪费了太多时间,真的需要一些帮助!
【问题讨论】:
【参考方案1】:创建签名url时要小心,如果生成签名url的代码在IAM上没有正确的权限,生成预签名url时不会出现任何错误,但是在生成签名url时会出现错误使用网址。
【讨论】:
【参考方案2】:这可能是因为您的请求标头与您在生成预签名 URL 时使用的标头不匹配。
如果您没有提及默认标头,则您使用的 HTTP 库可能会添加默认标头,例如 Content-Type
。我知道Axios
会这样做。
【讨论】:
【参考方案3】:AWS 返回 SignatureDoesNotMatch 错误 (403) 的原因通常是 secret key 不正确
【讨论】:
【参考方案4】:好吧,现在我觉得自己很愚蠢:
刚刚用 Postman 测试了说 Presigned PUT URL 并且不知何故它可以工作:
确保输入预签名 URL,选择 PUT,然后选择二进制并添加文件。
如果有人觉得它有用,我会保留它。
【讨论】:
以上是关于测试 AWS S3 Presigned Url 返回 403 Forbidden (Nodejs)的主要内容,如果未能解决你的问题,请参考以下文章
通过 Flutter App 的 PreSigned URL 将文件上传到 S3。但是当我下载它时文件已损坏
PUT NSData 从 S3 到 PreSigned URL,Alamofire.upload(...) 在 iOS 8 上不起作用
generate_presigned_url boto3 在使用 cloudfront 调用时生成相同的 URL 直到过期
在 Django 中,仅生成 s3 客户端 generate_presigned_post,内容类型为 mp4 文件上传