AWS signed URL too long to shorten

2019-06-04 22:37发布

问题:

I am creating a signed URL with AWS so I can safely pass this URL to another API for temporary use. The signed URL points to a S3 resource. The problem is the other API does not accept such long links. Therefore I am trying to shorten it. I tried to use shorteners like goo.gl or bit.ly to no avail because the URL was too long for them. I even built my own private shortener with AWS (AWS url shortener) but it had the same problem: "The length of website redirect location cannot exceed 2,048 characters.".

I am creating the signed URLs in iOS (Swift) with AWSS3PreSignedURLBuilder.default().getPreSignedURL(preSignedURLRequest) while using AWS Cognito as an unauthorised user.

I have tried the following things to no avail:

  • Choose the shortest possible S3 bucket name with 3 characters
  • Shorten the filename as much as possible. I limited the file name to 10 characters plus file extension name (14 characters in total). Shorter file names are not viable for me because they should be unique to a certain extent.

But even with all these minor tweaks the signed URL returned by AWS is sometimes too long. Especially the token parameter (X-Amz-Security-Token) seems to be really long. With my minor tweaks I sometimes get URLs shorter than 2,048 characters but sometimes slightly longer. I would like to find a solution which guarantees me that the URL is not too long and can be shortened.

In my own private AWS URL shortener the following code snippet creates the S3 object which redirects to the actual long URL.

s3.putObject({
    Bucket: s3_bucket,
    Key: key_short,
    Body: "",
    WebsiteRedirectLocation: url_long,
    ContentType: "text/plain"
  },
  (err, data) => {
    if (err) {
      console.log(err);
      done("", err.message);
    } else {
      const ret_url = "https://" + cdn_prefix + "/" + id_short;
      console.log("Success, short_url = " + ret_url);
      done(ret_url, "");
    }
  });

The method returns with the following error

The length of website redirect location cannot exceed 2,048 characters.

The documentation of putObject for the header "x-amz-website​-redirect-location" in the object meta states the following (see: put object documentation):

The length of the value is limited to 2 KB

How can I make sure that the initial AWS signed URL is not too long for the URL shorteners?

EDIT:

One of the problems I have identified is that I create the signed URL as an unauthenticated user in AWS Cognito. Therefore the signed URL includes this ridiculously long token as a parameter. I did not want to embed my accessKey and shortKey in the iOS App thats why I switched to AWS Cognito (see aws cognito). But currently there are no authorised users just unauthorised ones and I need to create the signed URL as an unauthorised AWS Cognito user. If I create the signed URL with with a regular credentials using accessKey and shortKey I get a much shorter URL. But for that I would have to embed my accessKey and shortKey in the iOS app which is not recommended.

回答1:

There is an older method of generating pre-signed URLs that produces a very short link, eg:

https://s3-ap-southeast-2.amazonaws.com/my-bucket/foo.png?AWSAccessKeyId=AKI123V12345RYTP123&Expires=1508620600&Signature=oB1/jca2JFXw5DbN7gBKEXkUQk8%3D

However, this pre-dates sigv4 so it does not work in the newer regions (Frankfurt onwards).

You can find sample code at:

  • mdwhatcott/s3_presign.py
  • S3 Generate Pre Signed Url
  • It can also be used to sign for uploads: Correct S3 Policy For Pre-Signed URLs


回答2:

I solved the problem by creating an AWS lambda for creating a presigned URL and returning the presigned URL. The presigned URL allows the caller to access (getObject) the S3 resource. There are two options regarding this:

  1. The role assigned to the AWS lambda has the S3 permission for getObject. The resulting presigned URL will have a much shorter token included than the presigned URL created with the temporary credentials issued by AWS Cognito in the iOS app.
  2. Embed the access key and secret key of a role with the S3 permission for getObject directly into the AWS lambda which will give you an even shorter URL because there is no token included in the resulting presigned URL. (e.g. sample AWS code)

I call this lambda from within my iOS app as an unauthorised cognito user. After receiving the presigned URL from the AWS lambda I am able to shorten it because with this method the presigned URLs are much shorter.