Skip to content

Commit f401f4e

Browse files
authored
aws/signer/v4: Fix X-Amz-Content-Sha256 being in to query for presign (#188)
Fixes the bug which would allow the X-Amz-Content-Sha256 header to be promoted to the query string when presigning a S3 request. This bug also was preventing users from setting their own sha256 value for a presigned URL. Presigned requests generated with the custom sha256 would of always failed with invalid signature. S3 presign requests without a user specified X-Amz-Content-Sha256 will no longer include the X-Amz-Content-Sha256 in the header nor query. The X-Amz-Content-Sha256 header only needs to be set if it contains a non UNSIGNED-PAYLOAD value. Related to aws/aws-sdk-go#1974
1 parent bd12807 commit f401f4e

File tree

3 files changed

+40
-11
lines changed

3 files changed

+40
-11
lines changed

aws/signer/v4/functional_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func TestPresignHandler(t *testing.T) {
5252
expectedHost := "bucket.s3.mock-region.amazonaws.com"
5353
expectedDate := "19700101T000000Z"
5454
expectedHeaders := "content-disposition;host;x-amz-acl"
55-
expectedSig := "a46583256431b09eb45ba4af2e6286d96a9835ed13721023dc8076dfdcb90fcb"
55+
expectedSig := "2d76a414208c0eac2a23ef9c834db9635ecd5a0fbb447a00ad191f82d854f55b"
5656
expectedCred := "AKID/19700101/mock-region/s3/aws4_request"
5757

5858
u, _ := url.Parse(urlstr)
@@ -75,8 +75,8 @@ func TestPresignHandler(t *testing.T) {
7575
if e, a := "300", urlQ.Get("X-Amz-Expires"); e != a {
7676
t.Errorf("expect %v, got %v", e, a)
7777
}
78-
if e, a := "UNSIGNED-PAYLOAD", urlQ.Get("X-Amz-Content-Sha256"); e != a {
79-
t.Errorf("expect %v, got %v", e, a)
78+
if a := urlQ.Get("X-Amz-Content-Sha256"); len(a) != 0 {
79+
t.Errorf("expect no content sha256 got %v", a)
8080
}
8181

8282
if e, a := "+", urlstr; strings.Contains(a, e) { // + encoded as %20
@@ -105,7 +105,7 @@ func TestPresignRequest(t *testing.T) {
105105
expectedHost := "bucket.s3.mock-region.amazonaws.com"
106106
expectedDate := "19700101T000000Z"
107107
expectedHeaders := "content-disposition;host;x-amz-acl"
108-
expectedSig := "a46583256431b09eb45ba4af2e6286d96a9835ed13721023dc8076dfdcb90fcb"
108+
expectedSig := "2d76a414208c0eac2a23ef9c834db9635ecd5a0fbb447a00ad191f82d854f55b"
109109
expectedCred := "AKID/19700101/mock-region/s3/aws4_request"
110110
expectedHeaderMap := http.Header{
111111
"x-amz-acl": []string{"public-read"},
@@ -135,8 +135,8 @@ func TestPresignRequest(t *testing.T) {
135135
if e, a := "300", urlQ.Get("X-Amz-Expires"); e != a {
136136
t.Errorf("expect %v, got %v", e, a)
137137
}
138-
if e, a := "UNSIGNED-PAYLOAD", urlQ.Get("X-Amz-Content-Sha256"); e != a {
139-
t.Errorf("expect %v, got %v", e, a)
138+
if a := urlQ.Get("X-Amz-Content-Sha256"); len(a) != 0 {
139+
t.Errorf("expect no content sha256 got %v", a)
140140
}
141141

142142
if e, a := "+", urlstr; strings.Contains(a, e) { // + encoded as %20

aws/signer/v4/v4.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ var requiredSignedHeaders = rules{
133133
"X-Amz-Server-Side-Encryption-Customer-Key-Md5": struct{}{},
134134
"X-Amz-Storage-Class": struct{}{},
135135
"X-Amz-Website-Redirect-Location": struct{}{},
136+
"X-Amz-Content-Sha256": struct{}{},
136137
},
137138
},
138139
patterns{"X-Amz-Meta-"},
@@ -643,14 +644,22 @@ func (ctx *signingCtx) buildSignature() {
643644
func (ctx *signingCtx) buildBodyDigest() {
644645
hash := ctx.Request.Header.Get("X-Amz-Content-Sha256")
645646
if hash == "" {
646-
if ctx.unsignedPayload || (ctx.isPresign && ctx.ServiceName == "s3") {
647+
includeSHA256Header := ctx.unsignedPayload ||
648+
ctx.ServiceName == "s3" ||
649+
ctx.ServiceName == "glacier"
650+
651+
s3Presign := ctx.isPresign && ctx.ServiceName == "s3"
652+
653+
if ctx.unsignedPayload || s3Presign {
647654
hash = "UNSIGNED-PAYLOAD"
655+
includeSHA256Header = !s3Presign
648656
} else if ctx.Body == nil {
649657
hash = emptyStringSHA256
650658
} else {
651659
hash = hex.EncodeToString(makeSha256Reader(ctx.Body))
652660
}
653-
if ctx.unsignedPayload || ctx.ServiceName == "s3" || ctx.ServiceName == "glacier" {
661+
662+
if includeSHA256Header {
654663
ctx.Request.Header.Set("X-Amz-Content-Sha256", hash)
655664
}
656665
}

aws/signer/v4/v4_test.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,16 +197,36 @@ func TestSignBodyGlacier(t *testing.T) {
197197
}
198198
}
199199

200-
func TestPresignEmptyBodyS3(t *testing.T) {
201-
req, body := buildRequest("s3", "us-east-1", "hello")
200+
func TestPresign_SignedPayload(t *testing.T) {
201+
req, body := buildRequest("glacier", "us-east-1", "hello")
202202
signer := buildSigner()
203-
signer.Presign(req, body, "s3", "us-east-1", 5*time.Minute, time.Now())
203+
signer.Presign(req, body, "glacier", "us-east-1", 5*time.Minute, time.Now())
204+
hash := req.Header.Get("X-Amz-Content-Sha256")
205+
if e, a := "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", hash; e != a {
206+
t.Errorf("expect %v, got %v", e, a)
207+
}
208+
}
209+
210+
func TestPresign_UnsignedPayload(t *testing.T) {
211+
req, body := buildRequest("service-name", "us-east-1", "hello")
212+
signer := buildSigner()
213+
signer.UnsignedPayload = true
214+
signer.Presign(req, body, "service-name", "us-east-1", 5*time.Minute, time.Now())
204215
hash := req.Header.Get("X-Amz-Content-Sha256")
205216
if e, a := "UNSIGNED-PAYLOAD", hash; e != a {
206217
t.Errorf("expect %v, got %v", e, a)
207218
}
208219
}
209220

221+
func TestPresign_UnsignedPayload_S3(t *testing.T) {
222+
req, body := buildRequest("s3", "us-east-1", "hello")
223+
signer := buildSigner()
224+
signer.Presign(req, body, "s3", "us-east-1", 5*time.Minute, time.Now())
225+
if a := req.Header.Get("X-Amz-Content-Sha256"); len(a) != 0 {
226+
t.Errorf("expect no content sha256 got %v", a)
227+
}
228+
}
229+
210230
func TestSignPrecomputedBodyChecksum(t *testing.T) {
211231
req, body := buildRequest("dynamodb", "us-east-1", "hello")
212232
req.Header.Set("X-Amz-Content-Sha256", "PRECOMPUTED")

0 commit comments

Comments
 (0)