Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Amazon S3 - How to properly build URLs pointing to the objects in a bucket?

Tags:

c#

url

amazon-s3

I'm using the Amazon S3 environment to store images for a C# Webapplication. From the S3 documentation I learned, that the basic URL to access an object looks like

http://[bucket-name].S3.amazonaws.com/[key]

I know that one can build expiring URLs to the objects in a bucket. Two questions:

  1. Should one generally use expiring URL's?
  2. How would I build an expiring url?
like image 954
Mats Avatar asked May 10 '11 11:05

Mats


People also ask

What is true about Amazon S3 URLs for accessing a bucket?

Amazon S3 supports both virtual-hosted–style and path-style URLs to access a bucket. Because buckets can be accessed using path-style and virtual-hosted–style URLs, we recommend that you create buckets with DNS-compliant bucket names. For more information, see Bucket restrictions and limitations.

Can I point domain to S3 bucket?

You can only test the endpoint for your domain bucket because your subdomain bucket is set up for website redirect and not static website hosting. Amazon S3 does not support HTTPS access to the website. If you want to use HTTPS, you can use Amazon CloudFront to serve a static website hosted on Amazon S3.

How do I create a URL for Amazon S3?

To generate a presigned URL using the AWS Management ConsoleSign in to the AWS Management Console and open the Amazon S3 console at https://console.aws.amazon.com/s3/ . In the Buckets list, choose the name of the bucket that contains the object that you want a presigned URL for.

Which of the URL formats can be used for accessing S3 objects?

An S3 bucket can be accessed through its URL. The URL format of a bucket is either of two options: http://s3.amazonaws.com/[bucket_name]/ http://[bucket_name].s3.amazonaws.com/


2 Answers

You only need to build expiring urls if you want to restrict access.

Here's some code to generate the signed url which expires in 3 mins.

using (var s3Client = AWSClientFactory.CreateAmazonS3Client("MyAccessKey", "MySecretKey"))
{
    GetPreSignedUrlRequest request = new GetPreSignedUrlRequest()
        .WithBucketName("MyBucketName")
        .WithKey("MyFileKey")
        .WithProtocol(Protocol.HTTP)
        .WithExpires(DateTime.Now.AddMinutes(3));

    string url = s3Client.GetPreSignedURL(request);
}
like image 76
Lee Gunn Avatar answered Sep 18 '22 15:09

Lee Gunn


This is code from S3SignURL, It uses no outside DLL's just pure core C#

https://github.com/DigitalBodyGuard/S3SignURL/

using System;
using System.Collections.Generic;
using System.Text;

namespace s3_polocySigning
{
    public static class Encode
    {
     //   static string thanks = "http://stackoverflow.com/questions/6999648/signing-post-form-in-c-sharp-for-uploading-to-amazon-s3";
        public static string BuildURL(string AccessKey, string SecretKey, DateTime timeToExpire, string BucketName, string FileKey)
        {
            System.Security.Cryptography.HMAC hmacProvider = System.Security.Cryptography.HMAC.Create();
            string returnString = string.Empty;
            hmacProvider.Key = System.Text.ASCIIEncoding.ASCII.GetBytes(SecretKey);
            string expirationString = ConvertToUnixTimestamp(timeToExpire).ToString();
            //System.Uri.UriSchemeHttp &/ System.Web.HttpUtility.UrlEncode
            string assembledRequest = "GET" + "\n" + "\n" + "\n" + expirationString + "\n" + "/" + BucketName + "/" + UrlEncode(FileKey);
            byte[] hashedSignature = hmacProvider.ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(assembledRequest));

            returnString = Convert.ToBase64String(hashedSignature);
            return "https://" + "s3.amazonaws.com/" + BucketName + "/" + FileKey + "?AWSAccessKeyId=" + AccessKey + "&Expires=" + expirationString + "&Signature=" + UrlEncode(returnString);
        }
        private static double ConvertToUnixTimestamp(DateTime ExpDate)
        {
            if (DateTime.MinValue == ExpDate)
                return  2133721337;
            DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            TimeSpan diff = ExpDate - origin;
            return Convert.ToDouble(Math.Floor(diff.TotalSeconds));
        }






        public static string GetSig(string policyStr, string secretKey)
        {
            policyStr = GetBase64_string(policyStr);
            var signature = new System.Security.Cryptography.HMACSHA1(GetBase64(secretKey));
            var bytes = GetBase64(policyStr);
            var moreBytes = signature.ComputeHash(bytes);
            var encodedCanonical = Convert.ToBase64String(moreBytes);
            return encodedCanonical;
        }
        public static string GetBase64_string(string policyStr)
        {
            policyStr = policyStr.Replace("/r", "").Replace("/n", "").Replace(System.Environment.NewLine, "\n");
            return Convert.ToBase64String(Encoding.ASCII.GetBytes(policyStr));
        }
        public static byte[] GetBase64(string policyStr)
        {
            return Encoding.ASCII.GetBytes(policyStr);
        }




       // ThanksTo = "http://www.west-wind.com/weblog/posts/2009/Feb/05/Html-and-Uri-String-Encoding-without-SystemWeb";
        // avoid useing System.Web.HttpUtility.UrlEncode

        /// <summary>
        /// UrlEncodes a string without the requirement for System.Web
        /// </summary>
        /// <param name="String"></param>
        /// <returns></returns>
        // [Obsolete("Use System.Uri.EscapeDataString instead")]
        public static string UrlEncode(string text)
        {
            // Sytem.Uri provides reliable parsing
            return System.Uri.EscapeDataString(text);
        }

        /// <summary>
        /// UrlDecodes a string without requiring System.Web
        /// </summary>
        /// <param name="text">String to decode.</param>
        /// <returns>decoded string</returns>
        public static string UrlDecode(string text)
        {
            // pre-process for + sign space formatting since System.Uri doesn't handle it
            // plus literals are encoded as %2b normally so this should be safe
            text = text.Replace("+", " ");
            return System.Uri.UnescapeDataString(text);
        }

        /// <summary>
        /// Retrieves a value by key from a UrlEncoded string.
        /// </summary>
        /// <param name="urlEncoded">UrlEncoded String</param>
        /// <param name="key">Key to retrieve value for</param>
        /// <returns>returns the value or "" if the key is not found or the value is blank</returns>
        public static string GetUrlEncodedKey(string urlEncoded, string key)
        {
            urlEncoded = "&" + urlEncoded + "&";

            int Index = urlEncoded.IndexOf("&" + key + "=", StringComparison.OrdinalIgnoreCase);
            if (Index < 0)
                return "";

            int lnStart = Index + 2 + key.Length;

            int Index2 = urlEncoded.IndexOf("&", lnStart);
            if (Index2 < 0)
                return "";

            return UrlDecode(urlEncoded.Substring(lnStart, Index2 - lnStart));
        }
    }
}
like image 28
user1906709 Avatar answered Sep 18 '22 15:09

user1906709