rzz24118
rzz24118

Reputation: 21

Download objects (files) using presigned url in AWS S3 doesn't work

I uploaded encrypted object using server-side encryption with customer-provided keys (SSE-C). Is it possible to download an object using pre-signed URL in AWS S3?

I tried like this

GeneratePresignedUrlRequest generatePresignedUrlRequest1 = new GeneratePresignedUrlRequest("bucketname", "objectpath")
       .withMethod(HttpMethod.GET)
       .withSSECustomerKey(new SSECustomerKey("base64mykey"))
       .withExpiration(new Date( System.currentTimeMillis() + (60 * 60 * 1000)));

The link is generated but when accessing it in the browser I'm getting this error The request signature we calculated does not match the signature you provided. Check your key and signing method. Is there a solution for this?

Upvotes: 0

Views: 1813

Answers (2)

antoweb
antoweb

Reputation: 31

Ok but with a curl lime this:

curl -v -T ${S3_UPLOAD_FILE} https://$S3_BUCKET.s3.amazonaws.com/${S3_DESTINATION_FILE} -H "Date: ${S3_DATE}" -H "Authorization: AWS ${S3_KEY}:${S3_SIGNATURE}" -H "Content-Type: ${S3_CONTENT_TYPE}" -H "Content-MD5: ${S3_MD5SUM}" -H "x-amz-server-side-encryption-customer-algorithm:${S3_SSEC_ALGORITHM}" -H "x-amz-server-side-encryption-customer-key:${S3_ENCRYPTION_KEY}" -H "x-amz-server-side-encryption-customer-key-MD5:${S3_ENCRYPTION_MD5}"

I can upload a file ro an s3 bucket with sse-c key. Wath about download?

Upvotes: 0

Michael - sqlbot
Michael - sqlbot

Reputation: 179404

SSE-C with pre-signed URLs may not work the way you expect.

The input to the request-signing algorithm includes all headers that begin with x-amz-*. This is significant for a reason that will become clearer in a moment.

The signature-generating code needs to know what these values will be when you actually make the request, and that is the only thing .withSSECustomerKey() does -- provides information that the signing algorithm needs so that the signature matches the actual request you eventually send.

The encryption key isn't actually embedded in the pre-signed URL. It needs to be supplied a second time, when the request is actually made.

When using server-side encryption with customer-provided encryption keys (SSE-C), you must provide encryption key information using the following request headers.

x-amz-server-side​-encryption​-customer-algorithm Use this header to specify the encryption algorithm. The header value must be AES256.

x-amz-server-side​-encryption​-customer-key Use this header to provide the 256-bit, base64-encoded encryption key for Amazon S3 to use to encrypt or decrypt your data.

x-amz-server-side​-encryption​-customer-key-MD5 Use this header to provide the base64-encoded 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a message integrity check to ensure that the encryption key was transmitted without error.

https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html

So you can use the pre-signed URL from a server using an HTTP client library (by injecting these headers with the request) or you could use it from the browser from Javascript, similarly, or with tools like Postman and Curl, but you can't use it as a clickable or pastable hyperlink, because a URL doesn't provide a way to specify HTTP headers. And, of course, it seems like a bad idea to use it from browser-side JS, too, since that reveals the encryption key in clear text... so if you are planning to download an object stored with SSE-C, that's only appropriate in a secure environment, anyway, because of the need to handle the key in the clear.

Upvotes: 2

Related Questions