Todos los productos
Search
Centro de documentos

Object Storage Service:Firma V4 (recomendada)

Última actualización: Sep 03, 2026

OSS requiere una firma V4 en cada solicitud PostObject para comprobar su autenticidad. El servidor de aplicaciones genera la firma a partir de los parámetros de la solicitud (política y expiración) mediante AccessKey Secret y HMAC-SHA256. OSS rechaza cualquier solicitud con una firma no válida.

Funcionamiento de las firmas POST

Las solicitudes POST utilizan el algoritmo de firma V4. El formulario y la política garantizan conjuntamente la autenticidad de la solicitud.

Elementos del formulario

Un formulario transmite el archivo y los metadatos en una solicitud POST. La tabla a continuación describe los elementos del formulario específicos de V4. Los elementos comunes se enumeran en PostObject form elements.

Parámetro

Tipo

Obligatorio

Descripción

x-oss-signature-version

String

Sí

Versión y algoritmo de la firma. El valor es fijo: OSS4-HMAC-SHA256.

x-oss-credential

String

Sí

Especifica el conjunto de parámetros para la clave derivada. El formato es el siguiente:

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

  • date: fecha de la solicitud en formato YYYYMMDD. Por ejemplo, 20231203.

  • region: ID de región de uso general de Alibaba Cloud. Ejemplo: cn-hangzhou.

  • oss: nombre del servicio solicitado. El valor es fijo: oss.

  • aliyun_v4_request: versión de la solicitud. El valor es fijo: aliyun_v4_request.

x-oss-date

String

Sí

Hora de la solicitud en formato ISO 8601. Ejemplo: 20231203T121212Z.

  • Se permite un desfase horario de hasta 15 minutos hacia atrás en el campo x-oss-date para compensar retrasos de red y desviaciones del reloj.

  • Una solicitud es válida durante un máximo de 7 días a partir del valor de x-oss-date. OSS rechaza las solicitudes donde x-oss-date tiene más de 7 días de antigüedad para prevenir ataques de repetición.

  • El valor de x-oss-date funciona como TimeStamp en StringToSign. Debe corresponder al mismo día que Date en la clave de firma y coincidir con el valor de x-oss-date en la política.

x-oss-signature

String

Sí

Hash HMAC-SHA256 de la política codificada en Base64, representado como una cadena hexadecimal.

Política

La política es un objeto JSON que restringe la carga de archivos al especificar nombres de bucket permitidos, prefijos de objetos, tiempos de expiración, métodos HTTP, tamaños de contenido y tipos de contenido.

Importante

Una política debe incluir expiration y conditions. La condición x-oss-security-token de este ejemplo solo es obligatoria cuando se usan credenciales temporales de STS. Omítala si utiliza un AccessKey de largo plazo.

{
  "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"]]
  ]
}

Los parámetros de la política se describen a continuación:

  • expiration

    Tiempo de expiración de la política en formato GMT ISO 8601. Ejemplo: 2023-12-03T13:00:00.000Z significa que la solicitud POST debe enviarse antes de las 13:00:00 UTC del 3 de diciembre de 2023.

  • conditions

    Define condiciones para los campos del formulario en la solicitud POST.

    Parámetro

    Tipo

    Obligatorio

    Descripción

    Tipo de coincidencia

    bucket

    String

    No

    Nombre del bucket.

    bucket

    x-oss-signature-version

    String

    Sí

    Versión y algoritmo de la firma. El valor es fijo: OSS4-HMAC-SHA256.

    x-oss-signature-version

    x-oss-credential

    String

    Sí

    Especifica el conjunto de parámetros para la clave derivada. El formato es el siguiente:

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

    • date: fecha de la solicitud.

    • region: ID de región de uso general de Alibaba Cloud. Ejemplo: cn-hangzhou.

    • oss: nombre del servicio solicitado. El valor es fijo: oss.

    • aliyun_v4_request: versión de la solicitud. El valor es fijo: aliyun_v4_request.

    x-oss-credential

    x-oss-security-token

    String

    No

    Obligatorio solo cuando se usan credenciales temporales de STS. Obtenga un token mediante la operación AssumeRole.

    x-oss-security-token

    x-oss-date

    String

    Sí

    Hora de la solicitud en formato ISO 8601. Ejemplo: 20231203T121212Z.

    • Se permite un desfase horario de hasta 15 minutos hacia atrás en el encabezado x-oss-date para compensar retrasos de red y desviaciones del reloj.

    • Una solicitud es válida durante un máximo de 7 días a partir del valor de x-oss-date. OSS rechaza las solicitudes donde x-oss-date ha expirado para prevenir ataques de repetición.

    • El valor de x-oss-date funciona como TimeStamp en StringToSign. Debe corresponder al mismo día que Date en la clave de firma y coincidir con el valor de x-oss-date en la política.

    x-oss-date

    content-length-range

    String

    No

    Tamaño mínimo y máximo permitido del objeto a cargar, en bytes.

    content-length-range

    success_action_status

    String

    No

    Código de estado HTTP que se devuelve tras una carga correcta.

    eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci

    key

    String

    No

    Nombre del objeto a cargar.

    eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci

    content-type

    String

    No

    Restringe el tipo de archivo de la carga.

    eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci

    cache-control

    String

    No

    Especifica el comportamiento de caché del objeto.

    eq, eq-ci, starts-with, starts-with-ci, in, in-ci, not-in, not-in-ci

Tipos de coincidencia para condiciones

Tipo de coincidencia

Descripción

content-length-range

Especifica el tamaño mínimo y máximo permitido del archivo a cargar. Por ejemplo, para permitir tamaños de archivo de 1 a 10 bytes, use ["content-length-range", 1, 10].

eq

El valor del campo del formulario debe coincidir exactamente con el valor especificado. Por ejemplo, para exigir que el campo key sea exactamente "a", use ["eq", "$key", "a"].

starts-with

El valor del campo del formulario debe comenzar con el prefijo especificado. Por ejemplo, para exigir que el valor de key comience con "user/user1", use ["starts-with", "$key", "user/user1"].

in

Especifica una lista de valores permitidos para el campo del formulario. Por ejemplo, para comprobar que una imagen cargada sea JPG o PNG, use ["in", "$content-type", ["image/jpg", "image/png"]].

not-in

Especifica una lista de valores no permitidos para el campo del formulario. Por ejemplo, para prohibir el valor "no-cache" en cache-control, use ["not-in", "$cache-control", ["no-cache"]].

eq-ci

El valor del campo del formulario debe coincidir exactamente con el valor especificado, sin distinguir mayúsculas de minúsculas. La comparación se realiza sobre cadenas en minúsculas. Por ejemplo, con ["eq-ci", "$key", "AbC"], nombres de objeto como "abc", "ABC" y "aBc" son coincidencias válidas.

starts-with-ci

El valor del campo del formulario debe comenzar con el prefijo especificado, sin distinguir mayúsculas de minúsculas. La comparación se realiza sobre cadenas en minúsculas. Por ejemplo, con ["starts-with-ci", "$key", "User/"], valores que comienzan con "user/", "USER/" o "User/" son coincidencias válidas.

in-ci

Especifica una lista de valores permitidos, sin distinguir mayúsculas de minúsculas. La comparación se realiza sobre cadenas en minúsculas. Por ejemplo, con ["in-ci", "$content-type", ["IMAGE/JPG", "image/PNG"]], valores como "image/jpg" e "IMAGE/PNG" son coincidencias válidas.

not-in-ci

Especifica una lista de valores no permitidos, sin distinguir mayúsculas de minúsculas. La comparación se realiza sobre cadenas en minúsculas. Por ejemplo, con ["not-in-ci", "$cache-control", ["No-Cache"]], valores como "no-cache", "NO-CACHE" y "No-Cache" quedan excluidos.

Nota

Cuando conditions contiene varias instrucciones para el mismo campo del formulario (como in y not-in), la última instrucción tiene prioridad. Evite condiciones conflictivas para el mismo campo.

Caracteres de escape en una política

En una política, el signo de dólar ($) indica una variable. Use \$ para representar un signo de dólar literal. La tabla a continuación enumera los caracteres de escape para el JSON de la política.

Carácter de escape

Descripción

\/

Barra diagonal

\\

Barra invertida

\

Comillas dobles

\$

Signo de dólar

\b

Espacio

\f

Salto de formulario

\n

Salto de línea

\r

Retorno de carro

\t

Tabulación horizontal

\uxxxx

Carácter Unicode

Proceso de cálculo de la firma

  1. Cree una política codificada en UTF-8.

  2. Construya la cadena a firmar.

    Codifique la política en Base64. El resultado es la cadena a firmar.

  3. Calcule la clave de firma.

    Genere una clave de firma mediante operaciones sucesivas de HMAC-SHA256 con su AccessKey Secret, fecha, región y nombre del servicio.

  4. Calcule la firma.

    Firme la cadena a firmar con HMAC-SHA256 mediante la clave de firma y convierta el resultado en una cadena hexadecimal. Esta es la firma final.

image

Ejemplos de cálculo de firma POST

  1. El ejemplo a continuación en Java calcula una firma POST para la política anterior.

    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);
            }
        }
    }

    Se obtiene el resultado a continuación:

    signature:3908473f7dbfb79a102eaaa44ca1edec8d7058ce3bd1c624d59eb437463bd5d6

    Temporary access credentials

    Cuando utilice credenciales temporales de STS, obtenga un token de seguridad mediante la operación 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);
            }
        }
    }

    Se obtiene el resultado a continuación:

    signature:1e09438f7ad01af6b3e144b42c98929c68f8d090ce07f4c277b18d8b62d0aa02
  2. El ejemplo a continuación en Python calcula una firma 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)

    Se obtiene el resultado a continuación:

    signature:9e85d56429245283b1aca5bc2dc31e0020b95ac2de9e9b81b496994db602ba1e