Remote signing

Aug 18, 2009 at 1:35 PM

Hi.

I was wondering how to use the library without embedding your secret AWS key in the application.

I have a client application and a webservice.
When a user of the client application wants to upload a file to Amazon S3, I would like the application to contact the webservice which would then make a signature that the application can use to contact Amazon S3.

As I see it right now, there is no way around distributing my secret AWS key with the client application if I would like to use the ThreeSharp library?

Aug 19, 2009 at 4:50 PM

This works just fine and there's no need to put your secret key in the client application.  On the server you create your policy document, base64 encode it and then encrypt if with an instance of HMACSHA1(Encoding.UTF8.GetBytes(awsSecretAccessKey), true);

Your secret key doesn't go over the wire, just the signed policy document.

e.g.

             DateTime utcExpiration = DateTime.UtcNow.Date.AddDays(30);       // policy document is valid for way longer than we need ...
            string expiration = utcExpiration.ToString("yyyy-MM-dd") +"T00:00:00Z";     // e.g. 2009-01-01T00:00:00Z

            string policyDocument = @"{""expiration"": """ + expiration + @""", ""conditions"": [ " +
                                        @"{""bucket"": """ + bucket + @"""}, " +
                                        @"[""starts-with"", ""$key"", """"], " +
                                        @"{""acl"": ""private""}, " +
                                        @"{""success_action_redirect"": """ + successUrl + @"""}, " +
                                        @"{""Content-Type"": ""image/jpeg""}, " +
                                        @"[""content-length-range"", 0, 6000111]" +                     // 6 Megabytes ish
                                      "]" +
                                    "}";

            log.Debug("policy = " + policyDocument);

            string b64policyDocument = Convert.ToBase64String(Encoding.UTF8.GetBytes(policyDocument), Base64FormattingOptions.None).Replace("\n", "").Replace("\r", "");

            HMACSHA1 hmacsha1 = new HMACSHA1(Encoding.UTF8.GetBytes(awsSecretAccessKey), true);
            byte[] policyBytes = Encoding.UTF8.GetBytes(b64policyDocument);
            string signature = Convert.ToBase64String(hmacsha1.ComputeHash(policyBytes), Base64FormattingOptions.None).Replace("\n", "").Replace("\r", "");

            string postUrl = "http://" + bucket + ".s3.amazonaws.com/";

            ImageUploadBasket result = new ImageUploadBasket()
                {
                    guid = guid,
                    key = key,
                    b64policyDocument = b64policyDocument,
                    signature = signature,
                    postUrl = postUrl,
                    successUrl = successUrl,
                    awsAccessKeyId = AmazonS3.awsAccessKeyId          // the non-secret part
                };

            return result;

In this example I pass back an "ImageUploadBasket" structure from the web service (SOAP) and the client then has all the information it needs to initiate a direct upload to S3.