OSS requires a V4 signature in each PostObject request to verify authenticity. Your application server derives the signature from request parameters (policy, expiration) using your AccessKey Secret and HMAC-SHA256. OSS rejects any request with an invalid signature.
How POST signatures work
POST requests use the V4 signature algorithm. The form and policy together ensure request authenticity.
Form elements
A form transmits the file and metadata in a POST request. The following table describes V4-specific form elements. Common form elements are listed in PostObject form elements.
Parameter | Type | Required | Description |
x-oss-signature-version | String | Yes | The signature version and algorithm. The value is fixed to |
x-oss-credential | String | Yes | Specifies the parameter set for the derived key. The format is as follows:
|
x-oss-date | String | Yes | The request time in ISO 8601 format. Example:
|
x-oss-signature | String | Yes | The HMAC-SHA256 hash of the Base64-encoded policy, represented as a hexadecimal string. |
Policy
The policy is a JSON object that constrains file uploads by specifying allowed bucket names, object prefixes, expiration times, HTTP methods, content sizes, and content types.
A policy must include expiration and conditions. The x-oss-security-token condition in this example is required only when using STS temporary credentials. Omit it when using a long-term AccessKey.
{
"expiration": "2023-12-03T13:00:00.000Z",
"conditions": [
{"bucket": "examplebucket"},
{"x-oss-signature-version": "OSS4-HMAC-SHA256"},
{"x-oss-credential": "AKIDEXAMPLE/20231203/cn-hangzhou/oss/aliyun_v4_request"},
{"x-oss-security-token": "CAIS******"},
{"x-oss-date": "20231203T121212Z"},
["content-length-range", 1, 10],
["eq", "$success_action_status", "201"],
["starts-with", "$key", "user/eric/"],
["in", "$content-type", ["image/jpg", "image/png"]],
["not-in", "$cache-control", ["no-cache"]]
]
}The policy parameters are described as follows:
expiration
The expiration time of the policy in ISO 8601 GMT format. Example:
2023-12-03T13:00:00.000Zmeans the POST request must be sent before 13:00:00 UTC on December 3, 2023.conditions
Defines conditions for form fields in the POST request.
Parameter
Type
Required
Description
Matching type
bucket
String
No
The bucket name.
bucket
x-oss-signature-version
String
Yes
The signature version and algorithm. The value is fixed to
OSS4-HMAC-SHA256.x-oss-signature-version
x-oss-credential
String
Yes
Specifies the parameter set for the derived key. The format is as follows:
<AccessKeyId>/<date>/<region>/oss/aliyun_v4_requestAccessKeyId: Your AccessKey ID.date: The request date.region: The general-purpose Alibaba Cloud region ID. Example:cn-hangzhou.oss: The requested service name. The value is fixed tooss.aliyun_v4_request: The request version. The value is fixed toaliyun_v4_request.
x-oss-credential
x-oss-security-token
String
No
Required only when using STS temporary credentials. Obtain a token by calling the AssumeRole operation.
x-oss-security-token
x-oss-date
String
Yes
The request time in ISO 8601 format. Example:
20231203T121212Z.A 15-minute backward time skew is allowed for the
x-oss-dateheader to account for network delays and clock drift.A request is valid for a maximum of 7 days from the
x-oss-datevalue. OSS rejects requests wherex-oss-dateis expired to prevent replay attacks.The
x-oss-datevalue serves as theTimeStampinStringToSign. It must fall on the same day as theDatein the signing key and match thex-oss-datevalue in the policy.
x-oss-date
content-length-range
String
No
The minimum and maximum allowed size of the object to upload, in bytes.
content-length-range
success_action_status
String
No
The HTTP status code to return after a successful upload.
eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci
key
String
No
The name of the object to upload.
eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci
content-type
String
No
Restricts the file type of the upload.
eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci
cache-control
String
No
Specifies the caching behavior of the object.
eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci
Signature calculation process
Create a UTF-8 encoded policy.
Construct the string to sign.
Base64-encode the policy. The result is the string to sign.
Calculate the signing key.
Derive a signing key by applying successive HMAC-SHA256 operations using your AccessKey Secret, date, region, and service name.
Calculate the signature.
HMAC-SHA256 sign the string to sign with the signing key, then convert the result to a hexadecimal string. This is the final signature.
POST signature calculation examples
The following Java example calculates a POST signature for the policy above.
AccessKey credentials
import com.aliyun.oss.common.utils.BinaryUtil; import org.apache.commons.codec.binary.Base64; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Map; import java.util.HashMap; import java.util.List; import java.util.ArrayList; import java.util.Arrays; public class Demo { public static void main(String[] args) throws Exception { // Before you run this code, make sure that the OSS_ACCESS_KEY_ID and OSS_ACCESS_KEY_SECRET environment variables are set. String accesskeyid = System.getenv().get("OSS_ACCESS_KEY_ID"); String accesskeysecret = System.getenv().get("OSS_ACCESS_KEY_SECRET"); // Step 1: Create a policy. ObjectMapper mapper = new ObjectMapper(); Map<String, Object> policy = new HashMap<>(); policy.put("expiration", "2024-12-03T13:00:00.000Z"); List<Object> conditions = new ArrayList<>(); Map<String, String> bucketCondition = new HashMap<>(); bucketCondition.put("bucket", "examplebucket"); conditions.add(bucketCondition); Map<String, String> signatureVersionCondition = new HashMap<>(); signatureVersionCondition.put("x-oss-signature-version", "OSS4-HMAC-SHA256"); conditions.add(signatureVersionCondition); Map<String, String> credentialCondition = new HashMap<>(); credentialCondition.put("x-oss-credential", accesskeyid + "/20241203/cn-hangzhou/oss/aliyun_v4_request"); conditions.add(credentialCondition); Map<String, String> dateCondition = new HashMap<>(); dateCondition.put("x-oss-date", "20241203T121212Z"); conditions.add(dateCondition); conditions.add(Arrays.asList("content-length-range", 1, 10)); conditions.add(Arrays.asList("eq", "$success_action_status", "201")); conditions.add(Arrays.asList("starts-with", "$key", "user/eric/")); conditions.add(Arrays.asList("in", "$content-type", Arrays.asList("image/jpg", "image/png"))); conditions.add(Arrays.asList("not-in", "$cache-control", Arrays.asList("no-cache"))); policy.put("conditions", conditions); String jsonPolicy = mapper.writeValueAsString(policy); // Step 2: Construct the string to sign. String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes())); System.out.println(stringToSign); // Step 3: Calculate the signing key. byte[] dateKey = hmacsha256(("aliyun_v4" + accesskeysecret).getBytes(), "20241203"); byte[] dateRegionKey = hmacsha256(dateKey, "cn-hangzhou"); byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss"); byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request"); // Step 4: Calculate the signature. byte[] result = hmacsha256(signingKey, stringToSign); String signature = BinaryUtil.toHex(result); System.out.println("signature:" + signature); } public static byte[] hmacsha256(byte[] key, String data) { try { // Initialize the HMAC key specification, specifying HmacSHA256 as the algorithm and using the provided key. SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256"); // Get a Mac instance, specifying HmacSHA256 as the algorithm. Mac mac = Mac.getInstance("HmacSHA256"); // Initialize the Mac object with the key. mac.init(secretKeySpec); // Perform the HMAC calculation. The doFinal method takes the data and returns the resulting hash as a byte array. byte[] hmacBytes = mac.doFinal(data.getBytes()); return hmacBytes; } catch (Exception e) { throw new RuntimeException("Failed to calculate HMAC-SHA256", e); } } }The following result is returned:
signature:3908473f7dbfb79a102eaaa44ca1edec8d7058ce3bd1c624d59eb437463bd5d6Temporary access credentials
When using temporary credentials from STS, obtain a security token by calling the AssumeRole operation.
import com.aliyun.oss.common.utils.BinaryUtil; import org.apache.commons.codec.binary.Base64; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import com.aliyun.sts20150401.models.AssumeRoleResponse; import com.aliyun.sts20150401.models.AssumeRoleResponseBody; import com.aliyun.tea.TeaException; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.*; public class Demo { // Initialize the STS client. public static com.aliyun.sts20150401.Client createStsClient() throws Exception { com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config() // Required. Make sure that the OSS_ACCESS_KEY_ID environment variable is set. .setAccessKeyId(System.getenv("OSS_ACCESS_KEY_ID")) // Required. Make sure that the OSS_ACCESS_KEY_SECRET environment variable is set. .setAccessKeySecret(System.getenv("OSS_ACCESS_KEY_SECRET")); // Endpoint config.endpoint = "sts.cn-hangzhou.aliyuncs.com"; return new com.aliyun.sts20150401.Client(config); } // Obtain temporary access credentials from STS. public static AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials getCredential() throws Exception { com.aliyun.sts20150401.Client client = Demo.createStsClient(); com.aliyun.sts20150401.models.AssumeRoleRequest assumeRoleRequest = new com.aliyun.sts20150401.models.AssumeRoleRequest() // Required. Make sure that the OSS_STS_ROLE_ARN environment variable is set. .setRoleArn(System.getenv("OSS_STS_ROLE_ARN")) .setRoleSessionName("role_session_name");// Custom session name. com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions(); try { // If you copy this code, print the API response on your own. AssumeRoleResponse response = client.assumeRoleWithOptions(assumeRoleRequest, runtime); // The credentials object contains the AccessKeyId, AccessKeySecret, and SecurityToken for subsequent operations. return response.body.credentials; } catch (TeaException error) { // This is for demonstration only. In a production environment, handle exceptions with care and do not ignore them. // Error message System.out.println(error.getMessage()); // Troubleshooting URL System.out.println(error.getData().get("Recommend")); com.aliyun.teautil.Common.assertAsString(error.message); } catch (Exception _error) { TeaException error = new TeaException(_error.getMessage(), _error); // This is for demonstration only. In a production environment, handle exceptions with care and do not ignore them. // Error message System.out.println(error.getMessage()); // Troubleshooting URL System.out.println(error.getData().get("Recommend")); com.aliyun.teautil.Common.assertAsString(error.message); } return null; } public static void main(String[] args) throws Exception { AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials sts_data = getCredential(); String accesskeyid = sts_data.accessKeyId; String accesskeysecret = sts_data.accessKeySecret; String securitytoken = sts_data.securityToken; // Step 1: Create a policy. ObjectMapper mapper = new ObjectMapper(); Map<String, Object> policy = new HashMap<>(); policy.put("expiration", "2024-12-03T13:00:00.000Z"); List<Object> conditions = new ArrayList<>(); Map<String, String> bucketCondition = new HashMap<>(); bucketCondition.put("bucket", "examplebucket"); conditions.add(bucketCondition); Map<String, String> signatureVersionCondition = new HashMap<>(); signatureVersionCondition.put("x-oss-signature-version", "OSS4-HMAC-SHA256"); conditions.add(signatureVersionCondition); Map<String, String> securityTokenCondition = new HashMap<>(); securityTokenCondition.put("x-oss-security-token", securitytoken); conditions.add(securityTokenCondition); Map<String, String> credentialCondition = new HashMap<>(); credentialCondition.put("x-oss-credential", accesskeyid + "/20241203/cn-hangzhou/oss/aliyun_v4_request"); conditions.add(credentialCondition); Map<String, String> dateCondition = new HashMap<>(); dateCondition.put("x-oss-date", "20241203T121212Z"); conditions.add(dateCondition); conditions.add(Arrays.asList("content-length-range", 1, 10)); conditions.add(Arrays.asList("eq", "$success_action_status", "201")); conditions.add(Arrays.asList("starts-with", "$key", "user/eric/")); conditions.add(Arrays.asList("in", "$content-type", Arrays.asList("image/jpg", "image/png"))); conditions.add(Arrays.asList("not-in", "$cache-control", Arrays.asList("no-cache"))); policy.put("conditions", conditions); String jsonPolicy = mapper.writeValueAsString(policy); // Step 2: Construct the string to sign. String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes())); // Step 3: Calculate the signing key. byte[] dateKey = hmacsha256(("aliyun_v4" + accesskeysecret).getBytes(), "20241203"); byte[] dateRegionKey = hmacsha256(dateKey, "cn-hangzhou"); byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss"); byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request"); // Step 4: Calculate the signature. byte[] result = hmacsha256(signingKey, stringToSign); String signature = BinaryUtil.toHex(result); System.out.println("signature:" + signature); } public static byte[] hmacsha256(byte[] key, String data) { try { // Initialize the HMAC key specification, specifying HmacSHA256 as the algorithm and using the provided key. SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256"); // Get a Mac instance, specifying HmacSHA256 as the algorithm. Mac mac = Mac.getInstance("HmacSHA256"); // Initialize the Mac object with the key. mac.init(secretKeySpec); // Perform the HMAC calculation. The doFinal method takes the data and returns the resulting hash as a byte array. byte[] hmacBytes = mac.doFinal(data.getBytes()); return hmacBytes; } catch (Exception e) { throw new RuntimeException("Failed to calculate HMAC-SHA256", e); } } }The following result is returned:
signature:1e09438f7ad01af6b3e144b42c98929c68f8d090ce07f4c277b18d8b62d0aa02The following Python example calculates a POST signature.
import base64 import hmac import hashlib import os def hmac_sha256(key, data): return hmac.new(key, data.encode('utf-8'), hashlib.sha256).digest() # Read the AccessKey ID and AccessKey Secret from environment variables. accesskeyid = os.getenv('OSS_ACCESS_KEY_ID') accesskeysecret = os.getenv('OSS_ACCESS_KEY_SECRET') # Print the AccessKey ID. print(accesskeyid) # Check if the environment variables were successfully retrieved. if not accesskeyid or not accesskeysecret: raise ValueError("Necessary environment variables not found: OSS_ACCESS_KEY_ID or OSS_ACCESS_KEY_SECRET") # Create the policy. policy = f'''{{ "expiration": "2025-01-01T00:00:00.000Z", "conditions": [ {{"x-oss-signature-version": "OSS4-HMAC-SHA256"}}, {{"x-oss-credential": "{accesskeyid}/20241105/cn-hangzhou/oss/aliyun_v4_request"}}, {{"x-oss-date": "20241105T065000Z"}} ] }}''' # Print the policy. print(policy) # Calculate the string to sign. string_to_sign = base64.b64encode(policy.encode('utf-8')).decode('utf-8') print(string_to_sign) # Calculate the signing key. date_key = hmac_sha256(f"aliyun_v4{accesskeysecret}".encode('utf-8'), "20241105") date_region_key = hmac_sha256(date_key, "cn-hangzhou") date_region_service_key = hmac_sha256(date_region_key, "oss") signing_key = hmac_sha256(date_region_service_key, "aliyun_v4_request") # Calculate the signature. result = hmac_sha256(signing_key, string_to_sign) signature = result.hex() print("signature:", signature)The following result is returned:
signature:9e85d56429245283b1aca5bc2dc31e0020b95ac2de9e9b81b496994db602ba1e