AWS S3 pre-signed URL 具有强制内容-md5
AWS S3 pre-signed URL with enforced content-md5
我正在尝试将 S3 的 pre-signed URL 与强制的 Content-MD5 一起使用。因此,我基本上是在尝试效仿他们 Docs 的例子。显然我做错了什么。
这是我尝试上传的文件的校验和:
➜ md5 testfile.txt
MD5 (testfile.txt) = ce0a4a83c88c2e7562968f03076ae62f
代码如下:
func main() {
sess, err := session.NewSession(&aws.Config{
Region: aws.String("eu-central-1")},
)
svc := s3.New(sess)
resp, _ := svc.PutObjectRequest(&s3.PutObjectInput{
Bucket: aws.String("bucket"),
Key: aws.String("testfile.txt"),
})
md5 := "ce0a4a83c88c2e7562968f03076ae62f" // hard coded & pasted from "$ md5 testfile.txt"
md5s := base64.StdEncoding.EncodeToString([]byte(md5))
resp.HTTPRequest.Header.Set("Content-MD5", md5s)
url, err := resp.Presign(15 * time.Minute)
if err != nil {
fmt.Println("error presigning request", err)
return
}
fmt.Printf("curl -XPUT -H \"Content-MD5: %s\" %s --upload-file %s\n\n", md5s, url, "testfile.txt")
}
哪个 应该 给我一个 ready-to-use curl 命令,例如:curl -XPUT -H "Content-MD5: Y2UwYTRhODNjODhjMmU3NTYyOTY4ZjAzMDc2YWU2MmY=" https://bucket.s3.eu-central-1.amazonaws.com/testfile.txt<super-long-url> --upload-file testfile.txt
不幸的是,请求总是失败并显示此消息:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>InvalidDigest</Code><Message>The Content-MD5 you specified was invalid.</Message><Content-MD5>Y2UwYTRhODNjODhjMmU3NTYyOTY4ZjAzMDc2YWU2MmY=</Content-MD5><RequestId>24F73D8948824799</RequestId><HostId>uKgSjxi03P4EvBk+Yo/EzxqWT0AI6AN3FPB2bKKAtgVjp8t4q2Ku+Tvui108vIQgcwgfvQdwmrk=</HostId></Error>
因为我有点不确定我是否应该使用 MD5 的 base64 请求,所以我尝试使用普通的 MD5 以及
的响应
<?xml version="1.0" encoding="UTF-8"?>
<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><accesskeyid></AWSAccessKeyId><StringToSign>AWS4-HMAC-SHA256
20180127T215418Z
20180127/eu-central-1/s3/aws4_request
e9580e510332d2fe8811209a8952e849022a56b93a02eca037fa43a10dec680f</StringToSign><SignatureProvided><signature></SignatureProvided><StringToSignBytes>41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 0a 32 30 31 38 30 31 32 37 54 32 31 35 34 31 38 5a 0a 32 30 31 38 30 [...]
</StringToSignBytes><CanonicalRequest>PUT
/testfile.txt
X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=<accesskeyid>%2F20180127%2Feu-central-1%2Fs3%2Faws4_request&X-Amz-Date=20180127T215418Z&X-Amz-Expires=900&X-Amz-SignedHeaders=content-md5%3Bhost
content-md5:ce0a4a83c88c2e7562968f03076ae62f
host:bucket.s3.eu-central-1.amazonaws.com
content-md5;host
UNSIGNED-PAYLOAD</CanonicalRequest><CanonicalRequestBytes>50 55 54 0a 2f 74 65 73 74 66 69 6c 65 2e 74 78 74 0a 58 2d 41 6d 7a 2d 41 6c 67 6f 72 69 74 68 6d 3d 41 57 53 34 2d 48 4d 41 43 [...]
] 44</CanonicalRequestBytes><RequestId>D92C97EE37BE602A</RequestId><HostId>VatR9cidZlUgq+Ngd5vkZ+wHNiumsCPhx/TvZnwImAkj/STZ0eXazVrwGPRdketBbICd91VLG9E=</HostId></Error>
只要我删除 header 设置 resp.HTTPRequest.Header.Set("Content-MD5", md5s)
并使用 curl -XPUT https://bucket.s3.eu-central-1.amazonaws.com/testfile.txt<super-long-url> --upload-file testfile.txt
请求,上传就会立即生效。
我做错了什么?
由于 base64 编码的工作方式,md5 的 base64 表示形式始终正好是 24 个字符长,最后 2 个字符始终是 ==
。如您所见,您的长度大约是应有的两倍。
实际的 md5 digest/hash 只有 16 字节(128 位)长,并且是 non-printable 二进制 blob。
md5sum
实用程序和类似工具 return hex-encoded 可打印格式的摘要,长度为 32 字节,仅包含字符 0-9 和 a-f... 它是相同的值,但它已经通过 hex-encoding,因此如果您想根据Content-MD5
header.
openssl dgst -md5 -binary {filename}
将生成文件 md5 的二进制表示,或者您可以使用管道实际生成带有 openssl dgst -md5 -binary {filename} | base64
.
的最终 base-64 表示
请注意,这当然与 ssl 无关,但我在此示例中使用了 openssl dgst
工具,因为它可能是您的系统中已经拥有的东西,以及 base64
转换工具,它可能也已经存在了。
我正在尝试将 S3 的 pre-signed URL 与强制的 Content-MD5 一起使用。因此,我基本上是在尝试效仿他们 Docs 的例子。显然我做错了什么。
这是我尝试上传的文件的校验和:
➜ md5 testfile.txt
MD5 (testfile.txt) = ce0a4a83c88c2e7562968f03076ae62f
代码如下:
func main() {
sess, err := session.NewSession(&aws.Config{
Region: aws.String("eu-central-1")},
)
svc := s3.New(sess)
resp, _ := svc.PutObjectRequest(&s3.PutObjectInput{
Bucket: aws.String("bucket"),
Key: aws.String("testfile.txt"),
})
md5 := "ce0a4a83c88c2e7562968f03076ae62f" // hard coded & pasted from "$ md5 testfile.txt"
md5s := base64.StdEncoding.EncodeToString([]byte(md5))
resp.HTTPRequest.Header.Set("Content-MD5", md5s)
url, err := resp.Presign(15 * time.Minute)
if err != nil {
fmt.Println("error presigning request", err)
return
}
fmt.Printf("curl -XPUT -H \"Content-MD5: %s\" %s --upload-file %s\n\n", md5s, url, "testfile.txt")
}
哪个 应该 给我一个 ready-to-use curl 命令,例如:curl -XPUT -H "Content-MD5: Y2UwYTRhODNjODhjMmU3NTYyOTY4ZjAzMDc2YWU2MmY=" https://bucket.s3.eu-central-1.amazonaws.com/testfile.txt<super-long-url> --upload-file testfile.txt
不幸的是,请求总是失败并显示此消息:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>InvalidDigest</Code><Message>The Content-MD5 you specified was invalid.</Message><Content-MD5>Y2UwYTRhODNjODhjMmU3NTYyOTY4ZjAzMDc2YWU2MmY=</Content-MD5><RequestId>24F73D8948824799</RequestId><HostId>uKgSjxi03P4EvBk+Yo/EzxqWT0AI6AN3FPB2bKKAtgVjp8t4q2Ku+Tvui108vIQgcwgfvQdwmrk=</HostId></Error>
因为我有点不确定我是否应该使用 MD5 的 base64 请求,所以我尝试使用普通的 MD5 以及
的响应<?xml version="1.0" encoding="UTF-8"?>
<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><accesskeyid></AWSAccessKeyId><StringToSign>AWS4-HMAC-SHA256
20180127T215418Z
20180127/eu-central-1/s3/aws4_request
e9580e510332d2fe8811209a8952e849022a56b93a02eca037fa43a10dec680f</StringToSign><SignatureProvided><signature></SignatureProvided><StringToSignBytes>41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 0a 32 30 31 38 30 31 32 37 54 32 31 35 34 31 38 5a 0a 32 30 31 38 30 [...]
</StringToSignBytes><CanonicalRequest>PUT
/testfile.txt
X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=<accesskeyid>%2F20180127%2Feu-central-1%2Fs3%2Faws4_request&X-Amz-Date=20180127T215418Z&X-Amz-Expires=900&X-Amz-SignedHeaders=content-md5%3Bhost
content-md5:ce0a4a83c88c2e7562968f03076ae62f
host:bucket.s3.eu-central-1.amazonaws.com
content-md5;host
UNSIGNED-PAYLOAD</CanonicalRequest><CanonicalRequestBytes>50 55 54 0a 2f 74 65 73 74 66 69 6c 65 2e 74 78 74 0a 58 2d 41 6d 7a 2d 41 6c 67 6f 72 69 74 68 6d 3d 41 57 53 34 2d 48 4d 41 43 [...]
] 44</CanonicalRequestBytes><RequestId>D92C97EE37BE602A</RequestId><HostId>VatR9cidZlUgq+Ngd5vkZ+wHNiumsCPhx/TvZnwImAkj/STZ0eXazVrwGPRdketBbICd91VLG9E=</HostId></Error>
只要我删除 header 设置 resp.HTTPRequest.Header.Set("Content-MD5", md5s)
并使用 curl -XPUT https://bucket.s3.eu-central-1.amazonaws.com/testfile.txt<super-long-url> --upload-file testfile.txt
请求,上传就会立即生效。
我做错了什么?
由于 base64 编码的工作方式,md5 的 base64 表示形式始终正好是 24 个字符长,最后 2 个字符始终是 ==
。如您所见,您的长度大约是应有的两倍。
实际的 md5 digest/hash 只有 16 字节(128 位)长,并且是 non-printable 二进制 blob。
md5sum
实用程序和类似工具 return hex-encoded 可打印格式的摘要,长度为 32 字节,仅包含字符 0-9 和 a-f... 它是相同的值,但它已经通过 hex-encoding,因此如果您想根据Content-MD5
header.
openssl dgst -md5 -binary {filename}
将生成文件 md5 的二进制表示,或者您可以使用管道实际生成带有 openssl dgst -md5 -binary {filename} | base64
.
请注意,这当然与 ssl 无关,但我在此示例中使用了 openssl dgst
工具,因为它可能是您的系统中已经拥有的东西,以及 base64
转换工具,它可能也已经存在了。