Uploading a file via an HTML form
This section describes how to upload files from the browser to Object Storage using an HTML form.
Note
Objects larger than 5 GB cannot be uploaded using the form (see Quotas and limits in Object Storage).
All form fields after the file
field are ignored.
Overview
If you want to allow your service users to upload files to your bucket directly from the browser:
- Develop an HTML form with everything you need to send a request to Object Storage and place it on a page in your service.
- The user opens your service page from the browser and uses the form to upload their file to storage.
To set rules and restrictions for file uploads, attach your security policy to the form. You do not need a policy when your bucket is publicly available for writing with no restrictions.
To create a form, follow these steps:
- Develop a security policy to describe the parameters of the request to Object Storage. For example, your policy may set a limit on the uploaded object size.
- Generate a signature based on the security policy.
- Create an HTML form with a signed security policy you will provide your users with when uploading files.
HTML form
Generic layout of an HTML page with an upload form:
<html>
<head>
...
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
...
</head>
<body>
...
<form action="https://storage.yandexcloud.net/{bucket-name}" method="post" enctype="multipart/form-data">
...
<input .../>
...
</form>
...
</body>
</html>
An HTML form is described by the <form>
tag and consists of a declaration and some fields.
The form's declaration contains the following attributes:
action
: URL of the bucket to upload the object to.method
: HTTP method. Value:POST
.enctype
: Request content type. Value:multipart/form-data
.
The form fields contain a detailed description of the request to Object Storage and the restrictions that apply to it.
The form and its fields must be UTF-8 encoded. Set the charset
attribute of your page's <meta>
tag to UTF-8
:
<html>
<head>
...
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
...
Form fields
Object Storage supports form signing based on AWS Signature V2 and V4. The chosen signature method determines the set of fields in the form and their names. AWS Signature V2 is only supported for compatibility reasons. Avoid using it if possible.
Generic form layout:
<form action="https://storage.yandexcloud.net/{bucket-name}" method="post" enctype="multipart/form-data">
Key in storage:
<input type="input" name="key" value="object_key" /><br />
<!-- Request properties -->
<input type="hidden" name="X-Amz-Credential" value="access_key_id/date/ru-central1/s3/aws4_request" />
<input type="hidden" name="acl" value="predefined-acl-name" />
<input type="hidden" name="X-Amz-Algorithm" value="AWS4-HMAC-SHA256" />
<input type="hidden" name="X-Amz-Date" value="date" />
<input type="hidden" name="success_action_redirect" value="some-URL" />
<input type="hidden" name="policy" value="base64-encoded-policy-document" />
<input type="hidden" name="X-Amz-Signature" value="signature-string" />
<!-- Other required fields -->
File to upload:
<input type="file" name="file" /> <br />
<!-- Fields after "file" are ignored -->
<input type="submit" name="submit" value="Upload" />
</form>
<form action="https://storage.yandexcloud.net/{bucket-name}" method="post" enctype="multipart/form-data">
Key in storage:
<input type="input" name="key" value="object_key" />
<!-- Request properties -->
<input type="hidden" name="AWSAccessKeyId" value="access_key_id" />
<input type="hidden" name="acl" value="access_type" />
<input type="hidden" name="success_action_redirect" value="url" />
<input type="hidden" name="policy" value="base64-encoded-policy-document" />
<input type="hidden" name="signature" value="signature_string" />
<input type="hidden" name="Content-Type" value="content/type" />
<!-- Other required fields -->
File to upload:
<input type="file" name="file" /> <br />
<!-- Fields after "file" are ignored -->
<br />
<input type="submit" value="Upload file" />
</form>
Note
The following applies to AWS Signature V4 only.
Description of form fields:
Field | Description | Required |
---|---|---|
acl |
ACL for the object. You can set one of the predefined ACLs. For example, if you want to make an object public, use public-read . |
No |
Cache-Control |
Directives for caching data according to RFC 2616 |
No |
Content-Disposition |
Name under which Object Storage will suggest to save the object as a file when downloaded. Compliant with RFC 2616 |
No |
Content-Encoding |
Defines the content encoding according to RFC 2616 |
No |
Content-Type |
MIME type of the uploaded file. If you do not specify Content-Type , Object Storage will save the object as application/octet-stream . This can affect end user applications since they will not understand the file format (for example, a browser will be unable to render an image). |
No |
Expires |
Response expiration date. Compliant with RFC 2616 |
No |
key |
Object key. You can enter the whole key or a template in prefix/${filename} format, i.e., if you upload a file entitled some_file.jpg , the final object key will be prefix/some_file.jpg . |
Yes |
policy |
Security policy defining request permissions. Requests without a policy are treated as anonymous and are only processed for buckets with public write access. | Conditional |
X-Amz-Signature |
Signature of the policy to generate using a secret key. Required if the form has a security policy. |
Conditional |
success_action_redirect |
URL the user is redirected to when the file is successfully uploaded. If the value is not set, Object Storage returns the response specified in the success_action_status field. |
No |
success_action_status |
The response status after a successful upload. If success_action_redirect is not specified, Object Storage returns success_action_status . Response body is empty.Acceptable values: 200, 204 (default). |
No |
X-Amz-Algorithm |
Security policy signature algorithm. Value: AWS4-HMAC-SHA256 .Required if the form has a security policy. |
Conditional |
X-Amz-Credential |
Signature ID. A string in <access-key-id>/<date>/ru-central1/s3/aws4_request format, where <date> must match the X-Amz-Date field value and the date used to sign the policy.Required if the form has a security policy. |
Conditional |
X-Amz-Date |
Date in ISO8601 format, e.g., 20180719T000000Z . It must match the date in the X-Amz-Credential field (by value, not format) and the date used to sign the policy.Required if the form has a security policy. |
Conditional |
X-Amz-Storage-Class |
Storage class for the object. With an HTML form, you can only put an object in a standard storage. | No |
X-Amz-Meta-* |
User-defined object metadata. Object Storage considers all headers starting with X-Amz-Meta- as user-defined and does not process them. Instead, it saves them in their original format.The total size of user-defined headers must not exceed 2 KB. The size of user-defined data is determined as the length of the UTF-8 encoded string. The header names and their values are included when calculating the size. |
No |
X-Amz-Website- redirect-location |
If the bucket is configured as a website, this field sets a redirect from the specified object to any other object in the bucket or any URL on the web. The redirect is stored in the object metadata. | No |
file |
Input field that allows the user to select a file to upload. This field must be the last field in the form. All fields after file are ignored. You cannot upload more than one file in a single request. |
Yes |
Security policy
The HTML form contains a security policy that puts restrictions on uploadable files.
The security policy is a JSON document that may look as follows:
{
"expiration": "timestamp",
"conditions": [
{"bucket": "bucket-name"},
["starts-with", "$key", "users-uploads/"],
{"acl": "public-read"},
{"success_action_redirect": "http://localhost/"},
["starts-with", "$Content-Type", ""],
["content-length-range", 0, 1048576]
]
}
The expiration
field contains the policy expiration date in ISO86012019-07-22T15:39:36Z
. When the policy expires, Object Storage no longer accepts any files uploaded using the form.
The conditions
field contains a set of rules for the form fields. At least one rule must be specified for each form field.
Security policy rules can be of the following types:
Rule type | Description |
---|---|
Exact match | The form field value must be exactly the same as in the policy. For example, {"acl": "public-read"} . You can also use the alternative format: [ "eq", "$acl", "public-read" ] . |
Partial match | The form field value must start with the string specified in the policy. Here is an example: ["starts-with", "$key", "key_prefix"] . If an empty string is specified as a value, the field can take any value.Here is an example: ["starts-with", "$Content-Type", ""] . |
content-length-range |
Size limit for the object to upload. Here is an example: ["content-length-range", 0, 1048576] . |
Possible restrictions:
Element | Restriction type | Restriction scope |
---|---|---|
acl |
Exact and partial match. | acl form field. |
bucket |
Exact and partial match. | Bucket name. |
content-length-range |
content-length-range |
content-length-range |
key |
Exact and partial match. | key form field. It allows you to set the object key or prefix. |
success_action_redirect |
Exact and partial match. | success_action_redirect form field. |
success_action_status |
Exact and partial match. | success_action_status form field. |
X-Amz-* |
Exact match. | X-Amz-* form fields, except X-Amz-Meta-* . |
X-Amz-Meta-* |
Exact and partial match. | X-Amz-Meta-* form fields. |
Cache-Control Content-Disposition Content-Encoding Content-Type Expires |
Exact and partial match. | Form fields with the same names. |
If the key
field has a template format, the policy is applied after the user-defined file name is substituted into the template.
Security policy signature
The common policy signature algorithm is the following:
- Encode the policy JSON document in base64
. - Generate a signing key.
- Generate a policy signature.
Example of generating a form using boto3
The input conditions are as follows:
- Files must be saved into the
user-data
bucket with the/users/upload/
prefix. - Uploaded objects are publicly accessible for reading.
- If the upload is successful, the user is redirected to
https://example.com
.
To generate form fields, we will use boto3 SDK for Python:
aws_access_key_id = 'JK38EXAMP********'
aws_secret_access_key = 'ExamP1eSecReTKeykdo********'
endpoint = 'https://storage.yandexcloud.net'
s3 = boto3.client('s3',
aws_access_key_id=aws_access_key_id,
aws_secret_access_key=aws_secret_access_key,
region_name='ru-central1',
endpoint_url=endpoint,
config=botocore.client.Config(signature_version='s3v4'),
)
key = 'users/uploads/${filename}'
bucket = 'user-data'
conditions = [{"acl":"public-read"}, ["starts-with", "$key", "users/uploads"], {'success_action_redirect': 'https://example.com'}]
fields = {'success_action_redirect': 'https://example.com'}
prepared_form_fields = s3.generate_presigned_post(Bucket=bucket,
Key=key,
Conditions=conditions,
Fields=fields,
ExpiresIn=60 * 60)
print(prepared_form_fields)
The script will return a JSON document in the following format:
{
'url': u'https://storage.yandexcloud.net/user-data',
'fields': {
'X-Amz-Algorithm': 'AWS4-HMAC-SHA256',
'X-Amz-Date': '20190722T153936Z',
'success_action_redirect': 'https://example.com',
'X-Amz-Signature': '4bdfb2209fc30744458be10bc3b99361f2f50add20f2ca2425587a27********',
'key': 'users/uploads/${filename}',
'policy': u'eyJjb25kaXRpb25zIj...M5OjM2WiJ9',
'X-Amz-Credential': u'JK38EXAMP********/20190722/ru-central1/s3/aws4_request'}
}
Using the values from the returned document, you can build an HTML page with a file upload form:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<form action="https://storage.yandexcloud.net/user-data" method="post" enctype="multipart/form-data">
Key in storage:
<input type="input" name="key" value="users/uploads/${filename}" /><br />
<input type="hidden" name="X-Amz-Credential" value="JK38EXAMP********/20190722/ru-central1/s3/aws4_request" />
<input type="hidden" name="acl" value="public-read" />
<input type="hidden" name="X-Amz-Algorithm" value="AWS4-HMAC-SHA256" />
<input type="hidden" name="X-Amz-Date" value="20190722T153936Z" />
<input type="hidden" name="success_action_redirect" value="https://example.com" />
<input type="hidden" name="policy" value="eyJjb25kaXRpb25zIj...M5OjM2WiJ9" />
<input type="hidden" name="X-Amz-Signature" value="4bdfb2209fc30744458be10bc3b99361f2f50add20f2ca2425587a2722859f96" />
File to upload:
<input type="file" name="file" /> <br />
<input type="submit" name="submit" value="Upload" />
</form>
</body>
</html>