Browser-Based Upload using HTTP POST

0

This is my HTML POST Form.

<html>
  <head>
    
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    
  </head>
  <body>

  <form action="http://sigv4examplebucket.s3.amazonaws.com/" method="post" enctype="multipart/form-data">
    Key to upload: 
    <input type="input"  name="key" value="user/user1/${filename}" /><br />
    <input type="hidden" name="acl" value="public-read" />
    <input type="hidden" name="success_action_redirect" value="http://sigv4examplebucket.s3.amazonaws.com/successful_upload.html" />
    Content-Type: 
    <input type="input"  name="Content-Type" value="image/jpeg" /><br />
    <input type="hidden" name="x-amz-meta-uuid" value="14365123651274" /> 
    <input type="hidden" name="x-amz-server-side-encryption" value="AES256" /> 
    <input type="text"   name="X-Amz-Credential" value="AKIAIOSFODNN7EXAMPLE/20151229/us-east-1/s3/aws4_request" />
    <input type="text"   name="X-Amz-Algorithm" value="AWS4-HMAC-SHA256" />
    <input type="text"   name="X-Amz-Date" value="20151229T000000Z" />

    Tags for File: 
    <input type="input"  name="x-amz-meta-tag" value="" /><br />
    <input type="hidden" name="Policy" value='<Base64-encoded policy string>' />
    <input type="hidden" name="X-Amz-Signature" value="<signature-value>" />
    File: 
    <input type="file"   name="file" /> <br />
    <!-- The elements after this will be ignored -->
    <input type="submit" name="submit" value="Upload to Amazon S3" />
  </form>
  
</html>

I got this from the AWS S3 Docs shown below.

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

From AWS Console I have gotten my security credentials: Access Key = XXXX Secret Ket = XXXX

I am aware that I need to set values for "Policy" and "X-Amz-Signature" but I am not sure as to how to do that.

In the docs they have mentioned that I need to StringToSign and get the Policy/Signature but I am not sure how to do that.

Can someone help me as to how to generate Policy(Base64-encoded policy string) and Signature for my HTML FORM ?

asked 2 years ago544 views
1 Answer
1

Hi,

To base64 encode a string you can use online encoders (for example https://www.base64encode.org). Note: there are also operating system specific command line tools for base64 encoding for example base64 on Linux/MacOS. It is important that you make sure that the input has CRLF line endings. The online encoder lets you select CRLF in the dropdown.

The section Sample Policy and Form in the documentation you posted https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html shows how a policy document should look like. If you need help on how to change the values in the policy document to work with your S3 bucket please let me know. Otherwise you can copy that policy and decode it as I described in the previous paragraph (online decoder is probably the easiest). Now you have the base64 encoded policy.

To sign the base64 encoded policy you could use the following Python script (derived from this documentation https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html). Note: I am using this Python script because it is OS independent. There are also command line tools for hmac-sha256 cryptography. However, describing them for all the OS's is more complicated than just using a Python script.

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

"""
Important

The AWS SDKs sign API requests for you using the access key that you specify when you
configure the SDK. When you use an SDK, you don’t need to learn how to sign API requests.
We recommend that you use the AWS SDKs to send API requests, instead of writing your own code.

The following example is a reference to help you get started if you have a need to write
your own code to send and sign requests. The example is for reference only and is not
maintained as functional code.
"""

# AWS Version 4 signing example

# EC2 API (DescribeRegions)

# See: http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
# This version makes a GET request and passes the signature
# in the Authorization header.
import sys, os, base64, datetime, hashlib, hmac 

service = 's3'
date = '20151229'
region = 'us-east-1'
string_to_sign = "eyAiZXhwaXJhdGlvbiI6ICIyMDE1LTEyLTMwVDEyOjAwOjAwLjAwMFoiLA0KICAiY29uZGl0aW9ucyI6IFsNCiAgICB7ImJ1Y2tldCI6ICJzaWd2NGV4YW1wbGVidWNrZXQifSwNCiAgICBbInN0YXJ0cy13aXRoIiwgIiRrZXkiLCAidXNlci91c2VyMS8iXSwNCiAgICB7ImFjbCI6ICJwdWJsaWMtcmVhZCJ9LA0KICAgIHsic3VjY2Vzc19hY3Rpb25fcmVkaXJlY3QiOiAiaHR0cDovL3NpZ3Y0ZXhhbXBsZWJ1Y2tldC5zMy5hbWF6b25hd3MuY29tL3N1Y2Nlc3NmdWxfdXBsb2FkLmh0bWwifSwNCiAgICBbInN0YXJ0cy13aXRoIiwgIiRDb250ZW50LVR5cGUiLCAiaW1hZ2UvIl0sDQogICAgeyJ4LWFtei1tZXRhLXV1aWQiOiAiMTQzNjUxMjM2NTEyNzQifSwNCiAgICB7IngtYW16LXNlcnZlci1zaWRlLWVuY3J5cHRpb24iOiAiQUVTMjU2In0sDQogICAgWyJzdGFydHMtd2l0aCIsICIkeC1hbXotbWV0YS10YWciLCAiIl0sDQoNCiAgICB7IngtYW16LWNyZWRlbnRpYWwiOiAiQUtJQUlPU0ZPRE5ON0VYQU1QTEUvMjAxNTEyMjkvdXMtZWFzdC0xL3MzL2F3czRfcmVxdWVzdCJ9LA0KICAgIHsieC1hbXotYWxnb3JpdGhtIjogIkFXUzQtSE1BQy1TSEEyNTYifSwNCiAgICB7IngtYW16LWRhdGUiOiAiMjAxNTEyMjlUMDAwMDAwWiIgfQ0KICBdDQp9"

key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"

# Key derivation functions. See:
# http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-python
def sign(key, msg):
    return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()

kDate = sign(('AWS4' + key).encode('utf-8'), date)
kRegion = sign(kDate, region)
kService = sign(kRegion, service)
kSigning = sign(kService, 'aws4_request')
signature = hmac.new(kSigning, (string_to_sign).encode('utf-8'), hashlib.sha256).hexdigest()
print(signature)

If you modify the policy from the one in the documentation then you need to replace the string_to_sign with your new base64 encoded policy. If you use your own S3 bucket you will also have to update the date and region accordingly and replace the key with your access key.

The output of the python scrip is the signature.

If you have any questions on how to adapt the example from the documentation to using your own S3 bucket don't hesitate to ask.

May I ask why you are not using the AWS SDK for JavaScript?

AWS
answered 2 years ago
  • Uploading is working , i am trying to upload a .glb model to s3 but it's not working <input type="hidden" name="Content-Type" value="image/png"> because of this tag it's giving .png extension to every file which i download from s3, is there any way i can upload .glb file type using input tag ?

  • According to Wikipedia (https://en.wikipedia.org/wiki/GlTF) the internet media type for .glb files is model/gltf-binary. So you need to update your html and policy with the media type. Change <input type="input" name="Content-Type" value="image/png" /><br /> to <input type="input" name="Content-Type" value="model/gltf-binary" /><br />

    and in the policy document change ["starts-with", "$Content-Type", "image/"] to ["starts-with", "$Content-Type", "model/gltf-binary"]

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions