Pre-signed URLs and x-amz-acl

2020-08-22 03:54发布

问题:

I want to create a so-called "pre-signed" URL for uploading a particular object (PUT) to Amazon S3 bucket.

So far so good. I am using the python library boto to create an URL, that contains all necessary stuff (expires, signature and so on). The URL looks like this:

https://<bucketname>.s3.amazonaws.com/<key>?Signature=<sig>&Expires=<expires>&AWSAccessKeyId=<my key id>&x-amz-acl=public-read

Note the last parameter.

This, at least, as I understand, limits whoever uses this URL to uploading an object to a particular key in a particular bucket and also limits the canned ACL that will be set on the object to "public-read".

My last statement is quite incorrect though.

As it turns out, if you are using this URL, you can do the following with the x-amz-acl header (as opposed to the query string parameter with the same name, that you must set for the signature check to succeed):

  1. Set it to "public-read". The object's permissions will consist of two entries: "read" for "Everyone" and "full control" for bucket owner. This is quite expected.
  2. Omit the x-amz-acl header. The permissions on the object will be the same as the per-bucket default (bucket owner has full control). Why?
  3. Set it to "public-read-write". Result is exactly as in (1).
  4. Set it to "authenticated-read". "Authenticated users" get "read" permission, bucket owner has full control.
  5. Set it to "bucket-owner-read". Result is exactly as in (2). Bucket owner has full control, no other permissions are defined.
  6. Set it to "bucket-owner-full-control". Unsurprisingly, bucket owner will have full control.
  7. Set it to a non-existant canned ACL name and get an error.

So it seems, that

  1. The x-amz-acl header does not take part in the signature check, because you can change it at will and the request succeeds. The query string parameter, however, definitely is taken into account during the signature check.
  2. x-amz-acl query string parameter does not influence the object's permissions directly, as in, it does nothing on its own.
  3. If you send a x-amz-acl header, the resultant permissions never be
    • more restrictive for the bucket owner, than they are by default.
    • less restricvie for the non-bucket-owner.
  4. They can, however, be more restrictive for non-bucket-owner. That is, if you specify x-amz-acl=public-read in the query string, you can set the x-amz-acl header to authenticated-read and instead of a publicly readable object get an object, that can be only read by authenticated users.

What is the real relation between the x-amz-acl QS parameter and the header, that goes by the same name? Is there a way to restrict permissions on the object, that is to be uploaded via a PUT request to a so-called "pre-signed" URL?

回答1:

As I understand it (and I might be wrong here), the header x-amz-acl takes priority over the querystring argument--and they do serve the same purpose. The reason that only the querystring parameter is taken into account during the signature check is simply due to the fact that headers are not part of the signature check for the policy.

This page might help you; it helped me a lot when creating forms to upload directly to S3.



回答2:

It appears that you're using the wrong name for the acl parameter. According to their guide on signing requests, try using acl:

Signing and Authenticating REST Requests

If the request addresses a sub-resource, like ?versioning, ?location, ?acl, ?torrent, ?lifecycle, or ?versionid append the sub-resource, its value if it has one, and the question mark. Note that in case of multiple sub-resources, sub-resources must be lexicographically sorted by sub-resource name and separated by '&'. e.g. ?acl&versionId=value.

The list of sub-resources that must be included when constructing the CanonicalizedResource Element are: acl, lifecycle, location, logging, notification, partNumber, policy, requestPayment, torrent, uploadId, uploads, versionId, versioning, versions and website.