O OSS exige uma assinatura V4 em cada requisição PostObject para verifique a autenticidade. O servidor de aplicativos deriva a assinatura dos parâmetros da requisição (policy, expiration) usando o AccessKey Secret e HMAC-SHA256. O OSS rejeita qualquer requisição com assinatura inválida.
Como funcionam as assinaturas POST
As requisições POST utilizam o algoritmo de assinatura V4. O formulário e a policy garantem conjuntamente a autenticidade da requisição.
Elementos do formulário
Um formulário transmite o arquivo e os metadados em uma requisição POST. A tabela a seguir descreve os elementos específicos da V4. Os elementos comuns estão listados em Elementos de formulário PostObject.
Parâmetro | Tipo | Obrigatório | Descrição |
x-oss-signature-version | String | Sim | Versão e algoritmo da assinatura. Valor fixo: |
x-oss-credential | String | Sim | Conjunto de parâmetros para a chave derivada. Formato:
|
x-oss-date | String | Sim | Hora da requisição no formato ISO 8601. Exemplo:
|
x-oss-signature | String | Sim | Hash HMAC-SHA256 da policy codificada em Base64, representado como string hexadecimal. |
Policy
A policy é um objeto JSON que restringe uploads de arquivos ao especificar nomes de bucket permitidos, prefixos de objeto, tempos de expiração, métodos HTTP, tamanhos de conteúdo e tipos de conteúdo.
Uma policy deve incluir expiration e conditions. A condição x-oss-security-token neste exemplo é necessária apenas ao usar credenciais temporárias STS. Omita-a ao utilizar um AccessKey de longo prazo.
{
"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"]]
]
}
Os parâmetros da policy são descritos abaixo:
-
expiration
Tempo de expiração da policy no formato GMT ISO 8601. Exemplo:
2023-12-03T13:00:00.000Zindica que a requisição POST deve ser enviada antes das 13:00:00 UTC de 3 de dezembro de 2023. -
conditions
Define condições para os campos de formulário na requisição POST.
Parâmetro
Tipo
Obrigatório
Descrição
Tipo de correspondência
bucket
String
Não
Nome do bucket.
bucket
x-oss-signature-version
String
Sim
Versão e algoritmo da assinatura. Valor fixo:
OSS4-HMAC-SHA256.x-oss-signature-version
x-oss-credential
String
Sim
Conjunto de parâmetros para a chave derivada. Formato:
<AccessKeyId>/<date>/<region>/oss/aliyun_v4_requestAccessKeyId: Seu AccessKey ID.date: Data da requisição.region: ID da região de uso geral da Alibaba Cloud. Exemplo:cn-hangzhou.oss: Nome do serviço solicitado. Valor fixo:oss.aliyun_v4_request: Versão da requisição. Valor fixo:aliyun_v4_request.
x-oss-credential
x-oss-security-token
String
Não
Necessário apenas ao usar credenciais temporárias STS. Obtenha um token chamando a operação AssumeRole.
x-oss-security-token
x-oss-date
String
Sim
Hora da requisição no formato ISO 8601. Exemplo:
20231203T121212Z.O cabeçalho
x-oss-dateaceita um atraso de até 15 minutos para compensar latência de rede e dessincronização de relógio.A requisição permanece válida por no máximo 7 dias a partir do valor de
x-oss-date. O OSS rejeita requisições comx-oss-dateexpirado para evitar ataques de replay.O valor de
x-oss-dateserve comoTimeStampemStringToSign. Ele deve corresponder ao mesmo dia daDatena chave de assinatura e coincidir com o valor dex-oss-datena policy.
x-oss-date
content-length-range
String
Não
Tamanho mínimo e máximo permitido do objeto a ser enviado, em bytes.
content-length-range
success_action_status
String
Não
Código de status HTTP retornado após um upload bem-sucedido.
eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci
key
String
Não
Nome do objeto a ser enviado.
eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci
content-type
String
Não
Restringe o tipo de arquivo do upload.
eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci
cache-control
String
Não
Define o comportamento de cache do objeto.
eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci
Processo de cálculo da assinatura
Crie uma policy codificada em UTF-8.
-
Construa a string a ser assinada.
Codifique a policy em Base64. O resultado é a string a ser assinada.
-
Calcule a chave de assinatura.
Derive uma chave de assinatura aplicando operações sucessivas de HMAC-SHA256 usando seu AccessKey Secret, data, região e nome do serviço.
-
Calcule a assinatura.
Assine a string com a chave de assinatura usando HMAC-SHA256 e converta o resultado para uma string hexadecimal. Esta é a assinatura final.
Exemplos de cálculo de assinatura POST
-
O exemplo Java a seguir calcula uma assinatura POST para a policy acima.
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); } } }Resultado retornado:
signature:3908473f7dbfb79a102eaaa44ca1edec8d7058ce3bd1c624d59eb437463bd5d6Temporary access credentials
Ao usar credenciais temporárias do STS, obtenha um token de segurança chamando a operação AssumeRole.
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); } } }Resultado retornado:
signature:1e09438f7ad01af6b3e144b42c98929c68f8d090ce07f4c277b18d8b62d0aa02 -
O exemplo Python a seguir calcula uma assinatura POST.
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)Resultado retornado:
signature:9e85d56429245283b1aca5bc2dc31e0020b95ac2de9e9b81b496994db602ba1e