Todos os produtos
Search
Central de documentação

Object Storage Service:Assinatura POST V4

Última atualização: Jul 03, 2026

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: OSS4-HMAC-SHA256.

x-oss-credential

String

Sim

Conjunto de parâmetros para a chave derivada. Formato:

<AccessKeyId>/<date>/<region>/oss/aliyun_v4_request
  • AccessKeyId: Seu AccessKey ID.

  • date: Data da requisição no formato YYYYMMDD. Exemplo: 20231203.

  • 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-date

String

Sim

Hora da requisição no formato ISO 8601. Exemplo: 20231203T121212Z.

  • O campo x-oss-date aceita 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 com x-oss-date anterior a 7 dias para evitar ataques de replay.

  • O valor de x-oss-date serve como TimeStamp em StringToSign. Ele deve corresponder ao mesmo dia da Date na chave de assinatura e coincidir com o valor de x-oss-date na policy.

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.

Importante

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.000Z indica 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_request
    • AccessKeyId: 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-date aceita 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 com x-oss-date expirado para evitar ataques de replay.

    • O valor de x-oss-date serve como TimeStamp em StringToSign. Ele deve corresponder ao mesmo dia da Date na chave de assinatura e coincidir com o valor de x-oss-date na 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

Tipos de correspondência para condições

Tipo de correspondência

Descrição

content-length-range

Define o tamanho mínimo e máximo permitido para o arquivo a ser enviado. Por exemplo, para permitir arquivos de 1 a 10 bytes, use ["content-length-range", 1, 10].

eq

O valor do campo de formulário deve corresponder exatamente ao valor especificado. Por exemplo, para exigir que o campo key seja exatamente "a", use ["eq", "$key", "a"].

starts-with

O valor do campo de formulário deve começar com o prefixo especificado. Por exemplo, para exigir que o valor de key comece com "user/user1", use ["starts-with", "$key", "user/user1"].

in

Lista de valores permitidos para o campo de formulário. Por exemplo, para verifique se uma imagem enviada é JPG ou PNG, use ["in", "$content-type", ["image/jpg", "image/png"]].

not-in

Lista de valores proibidos para o campo de formulário. Por exemplo, para proibir o valor "no-cache" em cache-control, use ["not-in", "$cache-control", ["no-cache"]].

eq-ci

O valor do campo de formulário deve corresponder exatamente ao valor especificado, sem diferenciar maiúsculas de minúsculas. A comparação usa strings em minúsculas. Por exemplo, com ["eq-ci", "$key", "AbC"], nomes de objeto como "abc", "ABC" e "aBc" são correspondências válidas.

starts-with-ci

O valor do campo de formulário deve começar com o prefixo especificado, sem diferenciar maiúsculas de minúsculas. A comparação usa strings em minúsculas. Por exemplo, com ["starts-with-ci", "$key", "User/"], valores começando com "user/", "USER/" ou "User/" são correspondências válidas.

in-ci

Lista de valores permitidos, sem diferenciar maiúsculas de minúsculas. A comparação usa strings em minúsculas. Por exemplo, com ["in-ci", "$content-type", ["IMAGE/JPG", "image/PNG"]], valores como "image/jpg" e "IMAGE/PNG" são correspondências válidas.

not-in-ci

Lista de valores proibidos, sem diferenciar maiúsculas de minúsculas. A comparação usa strings em minúsculas. Por exemplo, com ["not-in-ci", "$cache-control", ["No-Cache"]], valores como "no-cache", "NO-CACHE" e "No-Cache" são excluídos.

Nota

Quando conditions contêm múltiplas instruções para o mesmo campo de formulário (como in e not-in), a última instrução tem precedência. Evite condições conflitantes para o mesmo campo.

Caracteres de escape para uma policy

Em uma policy, o cifrão ($) indica uma variável. Use \$ para representar um cifrão literal. A tabela a seguir lista os caracteres de escape para JSON de policy.

Caractere de escape

Descrição

\/

Barra normal

\\

Barra invertida

\

Aspas duplas

\$

Cifrão

\b

Espaço

\f

Alimentação de formulário

\n

Quebra de linha

\r

Retorno de carro

\t

Tabulação horizontal

\uxxxx

Caractere Unicode

Processo de cálculo da assinatura

  1. Crie uma policy codificada em UTF-8.

  2. Construa a string a ser assinada.

    Codifique a policy em Base64. O resultado é a string a ser assinada.

  3. 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.

  4. 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.

image

Exemplos de cálculo de assinatura POST

  1. 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:3908473f7dbfb79a102eaaa44ca1edec8d7058ce3bd1c624d59eb437463bd5d6

    Temporary 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
  2. 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