1

I'm just not getting this aws s3 to work. Tried several things now, including examples for angular (I don't want to use fineUploader!) and every time I get kind of the same errors. Right now I've got a pretty solid example of what needs to be done to get my error:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha256.js">    </script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/enc-base64-min.js"></script>
<script>
    var POLICY_JSON = { "expiration": "2014-12-20T12:00:00.000Z",
        "conditions": [
            {"bucket": "<AWS_BUCKET_NAME>"},
            ["starts-with", "$key", "russ"],
            {"acl": "public-read"},
            {"success_action_redirect": "http://localhost:3000/successful_upload.html"},
            ["starts-with", "$Content-Type", "image/"]
        ]};

    var policyBase64 = btoa((JSON.stringify(POLICY_JSON)));
    console.log('<POLICY> -->');
    console.log(policyBase64);
    var hash = CryptoJS.HmacSHA256(policyBase64, "<AWS_SECRET_KEY>");
    var base64 = CryptoJS.enc.Base64.stringify(hash);
    console.log('<SIGNATURE> -->');
    console.log(base64);

</script>


<form action="http://bucket.s3.amazonaws.com" method="post" enctype="multipart/form-data">
    <input type="hidden" name="acl" value="public-read" />
    <input type="hidden" name="success_action_redirect" value="http://localhost:3000/successful_upload.html" />
    <input type="hidden" name="AWSAccessKeyId" value="<AWS_ACCESS_KEY>" />
    <input type="hidden" name="Policy" value="<POLICY>" />
    <input type="hidden" name="Signature" value="<SIGNATURE>" />


    Key to upload: <input type="input" name="key" value="test.jpg" /><br />
    Content-Type: <input type="input" name="Content-Type" value="image/jpeg" /><br />
    File: <input type="file" name="file" /> <br />

    <input type="submit" name="submit" value="Upload to Amazon S3" />
</form>
</body>
</html>

Copy everything into a new .html file and open it once, to get the values into your console, fillout the form with the values that come out and open the index.html again. My big problem is the answer I get every time I try to upload something to our bucket.

<Error>
    <Code>InvalidRequest</Code>
    <Message>
        The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256.
    </Message>
    <RequestId><MYREQUESTID></RequestId>
    <HostId>
        <MYHOSTID>
    </HostId>
</Error>

Any suggestions? I'm working on this for 2 days now, searching and reading the amazon-documentation. It has to do with the signature I need to do (the new one aws uses seems to be named 'v4') and is used for the bucket since it's located in Frankfurt, Germany. But I'm just not getting how I can enhance my request to fit their needs.

3 Answers 3

2

You are building a V2 policy document, and signing it using HMAC with your AWS Secret, which is only done with V2.

With V4, you have to construct a "signing key" to use to sign the request, and include information you used to construct that key as your x-amz-credential in the policy, along with some other changes.

http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html

The actual method of generating the signature is also different.

http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html

You should probably start here...

http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-UsingHTTPPOST.html

As you have likely discovered by now, Frankfurt, and any other S3 regions deployed during or after the year 2014, do not support Signature Version 2. All regions support Signature Version 4.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks Michael, the thing is that it's so difficult to get. And there's no example online showing how to program that. The AWS documentation is just showing how to build the stringtosign. But thanks anyway, I will give the docs another chance.
@wegginho my 2nd link, above, explains the generation of the signing key and the signature, at the bottom of the page. I feel your pain -- coding it for the first time was less than fun but once you have a grasp of the big picture, it should become apparent how to get there from here.
Also, @SébastienStormacq has made an excellent, excellent point, below -- I assumed, maybe wrongly, that you were just testing this out in browser code. You definitely don't want to do it this way in your actual application, because it exposes your AWS credentials... a very serious security vulnerability. You have to create the policy and signature on the server, and send them to the browser... not create them in the browser.
1

While Michael's answer is correct, I also would like to add that we have a JavaScript SDK that allows you to call AWS API directly from the browser, with minimal JavaScript code. The SDK takes care of the low level details - what we call the undifferentiated heavy lifting - such as the HTTP connection, the retries and the signatures. More details at http://aws.amazon.com/sdk-for-browser/

Also, do not store your Secret Key in your JavaScript code on the client side (in the signature generation code). Anyone having access to your Access Key (visible in the form) and your Secret Key (in your JavaScript code) will have access to your account, with the privileges associated with the IAM policy for this pair of key.

Best practice, if you consider to work with S3 upload form, is to generate the form on the server side. By doing this, your Secret Key stays on your server and is not exposed on the client side.

6 Comments

I tried the AWS-SDK and it didn't work with the v4 signature Version. Sure I won't use my key in javascript frontend-code, this was just the simplest example to provide.
Is there a way to use the aws-sdk or aws-s3 overall without having to pass a user-login like facebook/google or anything else? Maybe there's a way to have a chat about that?
All our SDK do support Signature v4. With the Javascript SDK, this is done through the config object docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Config.html
You could always use multiple buckets, one for browser uploads, and another for storage, with two users in the IAM, whereas first user has just PutObject, AbortMultipartUpload, ListMultipartUploadParts on both "<arn>" and "<arn>/**" and second user has full access to both buckets. Once s3 upload completes, the redirect can initiate a object move from bucket1 to bucket2 with second user credentials. Thus the first credentials even if compromised, will only be able to upload files, but to a write only bucket and we can use bucket life cycle rule to clear any such orphans.
@wegginho With AWS-SDK, when initializing the s3 client using new AWS.S3(), you should pass a config object with a property signatureVersion: "v4"
|
1

Ok so the answer was not that simple but I solved it using this as a programmatic example from the real world. -> https://github.com/emil10001/AWS-NodeJS-AngularJS-Demos

And that's the server-code I ended up with:

        var urlPair = {};
        var key = crypto.createHash('sha1')
            .update(new Date().getTime().toString() + Math.random().toString())
            .digest('base64').toString();

        urlPair['s3Key'] = key;
        var putParams = {
            Bucket: 'bucket',
            Key: key,
            ACL: 'public-read',
            ContentType: 'application/octet-stream'
        };

        s3.getSignedUrl('putObject', putParams, function (err, url) {
            if (!!err) {
                console.log(err);
                return;
            }
            urlPair['s3PutUrl'] = url;
            urlPair['s3GetUrl'] = 'https://bucket.s3.amazonaws.com/' + qs.escape(key);
            res.json(urlPair);
            res.end();
        });

Both the s3PutUrl aswell as the s3GetUrl return valid statements to allow you to upload a file. But that's only part of it. Follow emil10001 through his example and you will end up having working code and a working environment!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.