Tous les produits
Search
Centre de documentation

Object Storage Service:Signature POST V4

Dernière mise à jour :Aug 18, 2026

OSS exige une signature V4 dans chaque requête PostObject pour en vérifier l'authenticité. Votre serveur d'application génère la signature à partir des paramètres de la requête (politique, expiration) en utilisant votre AccessKey Secret et l'algorithme HMAC-SHA256. OSS rejette toute requête dont la signature est invalide.

Fonctionnement des signatures POST

Les requêtes POST utilisent l'algorithme de signature V4. Le formulaire et la politique garantissent conjointement l'authenticité de la requête.

Éléments du formulaire

Un formulaire transmet le fichier et les métadonnées dans une requête POST. Le tableau suivant décrit les éléments spécifiques à la version V4. Les éléments courants sont répertoriés dans Éléments de formulaire PostObject.

Paramètre

Type

Obligatoire

Description

x-oss-signature-version

String

Oui

Version de la signature et algorithme. La valeur est fixée à OSS4-HMAC-SHA256.

x-oss-credential

String

Oui

Spécifie l'ensemble de paramètres pour la clé dérivée. Le format est le suivant :

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

  • date : date de la requête au format YYYYMMDD. Par exemple, 20231203.

  • region : ID de région Alibaba Cloud standard. Exemple : cn-hangzhou.

  • oss : nom du service demandé. La valeur est fixée à oss.

  • aliyun_v4_request : version de la requête. La valeur est fixée à aliyun_v4_request.

x-oss-date

String

Oui

Heure de la requête au format ISO 8601. Exemple : 20231203T121212Z.

  • Un décalage horaire arrière de 15 minutes est autorisé pour le champ x-oss-date afin de tenir compte des délais réseau et de la dérive des horloges.

  • Une requête est valide pendant un maximum de 7 jours à compter de la valeur x-oss-date. OSS rejette les requêtes dont la valeur x-oss-date est antérieure à plus de 7 jours pour prévenir les attaques par rejeu.

  • La valeur x-oss-date sert d'horodatage (TimeStamp) dans StringToSign. Elle doit correspondre au même jour que la date (Date) de la clé de signature et concorder avec la valeur x-oss-date de la politique.

x-oss-signature

String

Oui

Hachage HMAC-SHA256 de la politique encodée en Base64, représenté sous forme de chaîne hexadécimale.

Politique

La politique est un objet JSON qui restreint les téléchargements de fichiers en spécifiant les noms de compartiment autorisés, les préfixes d'objet, les délais d'expiration, les méthodes HTTP, les tailles de contenu et les types de contenu.

Important

Une politique doit inclure expiration et conditions. La condition x-oss-security-token de cet exemple n'est requise que lors de l'utilisation d'identifiants temporaires STS. Omettez-la si vous utilisez une AccessKey à long terme.

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

Les paramètres de la politique sont décrits ci-après :

  • expiration

    Délai d'expiration de la politique au format ISO 8601 GMT. Exemple : 2023-12-03T13:00:00.000Z signifie que la requête POST doit être envoyée avant 13:00:00 UTC le 3 décembre 2023.

  • conditions

    Définit les conditions applicables aux champs du formulaire dans la requête POST.

    Paramètre

    Type

    Obligatoire

    Description

    Type de correspondance

    bucket

    String

    Non

    Nom du compartiment.

    bucket

    x-oss-signature-version

    String

    Oui

    Version de la signature et algorithme. La valeur est fixée à OSS4-HMAC-SHA256.

    x-oss-signature-version

    x-oss-credential

    String

    Oui

    Spécifie l'ensemble de paramètres pour la clé dérivée. Le format est le suivant :

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

    • date : date de la requête.

    • region : ID de région Alibaba Cloud standard. Exemple : cn-hangzhou.

    • oss : nom du service demandé. La valeur est fixée à oss.

    • aliyun_v4_request : version de la requête. La valeur est fixée à aliyun_v4_request.

    x-oss-credential

    x-oss-security-token

    String

    Non

    Requis uniquement lors de l'utilisation d'identifiants temporaires STS. Obtenez un jeton en appelant l'opération AssumeRole.

    x-oss-security-token

    x-oss-date

    String

    Oui

    Heure de la requête au format ISO 8601. Exemple : 20231203T121212Z.

    • Un décalage horaire arrière de 15 minutes est autorisé pour l'en-tête x-oss-date afin de tenir compte des délais réseau et de la dérive des horloges.

    • Une requête est valide pendant un maximum de 7 jours à compter de la valeur x-oss-date. OSS rejette les requêtes dont la valeur x-oss-date a expiré pour prévenir les attaques par rejeu.

    • La valeur x-oss-date sert d'TimeStamp dans StringToSign. Elle doit correspondre au même jour que la Date de la clé de signature et concorder avec la valeur x-oss-date de la politique.

    x-oss-date

    content-length-range

    String

    Non

    Taille minimale et maximale autorisée de l'objet à télécharger, en octets.

    content-length-range

    success_action_status

    String

    Non

    Code d'état HTTP à renvoyer après un téléchargement réussi.

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

    key

    String

    Non

    Nom de l'objet à télécharger.

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

    content-type

    String

    Non

    Restreint le type de fichier du téléchargement.

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

    cache-control

    String

    Non

    Spécifie le comportement de mise en cache de l'objet.

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

Types de correspondance pour les conditions

Type de correspondance

Description

content-length-range

Spécifie la taille minimale et maximale autorisée du fichier à télécharger. Par exemple, pour autoriser des tailles de fichier comprises entre 1 et 10 octets, utilisez ["content-length-range", 1, 10].

eq

La valeur du champ du formulaire doit correspondre exactement à la valeur spécifiée. Par exemple, pour exiger que le champ key soit exactement « a », utilisez ["eq", "$key", "a"].

starts-with

La valeur du champ du formulaire doit commencer par le préfixe spécifié. Par exemple, pour exiger que la valeur key commence par « user/user1 », utilisez ["starts-with", "$key", "user/user1"].

in

Spécifie une liste de valeurs autorisées pour le champ du formulaire. Par exemple, pour vérifier qu'une image téléchargée est au format JPG ou PNG, utilisez ["in", "$content-type", ["image/jpg", "image/png"]].

not-in

Spécifie une liste de valeurs interdites pour le champ du formulaire. Par exemple, pour interdire la valeur « no-cache » pour cache-control, utilisez ["not-in", "$cache-control", ["no-cache"]].

eq-ci

La valeur du champ du formulaire doit correspondre exactement à la valeur spécifiée, sans tenir compte de la casse. La comparaison s'effectue sur des chaînes en minuscules. Par exemple, avec ["eq-ci", "$key", "AbC"], les noms d'objet tels que « abc », « ABC » et « aBc » sont tous des correspondances valides.

starts-with-ci

La valeur du champ du formulaire doit commencer par le préfixe spécifié, sans tenir compte de la casse. La comparaison s'effectue sur des chaînes en minuscules. Par exemple, avec ["starts-with-ci", "$key", "User/"], les valeurs commençant par « user/ », « USER/ » ou « User/ » sont toutes des correspondances valides.

in-ci

Spécifie une liste de valeurs autorisées, sans tenir compte de la casse. La comparaison s'effectue sur des chaînes en minuscules. Par exemple, avec ["in-ci", "$content-type", ["IMAGE/JPG", "image/PNG"]], les valeurs telles que « image/jpg » et « IMAGE/PNG » sont toutes deux des correspondances valides.

not-in-ci

Spécifie une liste de valeurs interdites, sans tenir compte de la casse. La comparaison s'effectue sur des chaînes en minuscules. Par exemple, avec ["not-in-ci", "$cache-control", ["No-Cache"]], les valeurs telles que « no-cache », « NO-CACHE » et « No-Cache » sont toutes exclues.

Remarque

Lorsque conditions contient plusieurs instructions pour le même champ de formulaire (telles que in et not-in), la dernière instruction prévaut. Évitez les conditions contradictoires pour un même champ.

Caractères d'échappement pour une politique

Dans une politique, le signe dollar ($) indique une variable. Utilisez \$ pour un signe dollar littéral. Le tableau suivant répertorie les caractères d'échappement pour le JSON de la politique.

Caractère d'échappement

Description

\/

Barre oblique

\\

Barre oblique inverse

\

Guillemet double

\$

Signe dollar

\b

Espace

\f

Saut de page

\n

Saut de ligne

\r

Retour chariot

\t

Tabulation horizontale

\uxxxx

Caractère Unicode

Processus de calcul de la signature

  1. Créez une politique encodée en UTF-8.

  2. Construisez la chaîne à signer.

    Encodez la politique en Base64. Le résultat constitue la chaîne à signer.

  3. Calculez la clé de signature.

    Dérivez une clé de signature en appliquant des opérations HMAC-SHA256 successives à l'aide de votre AccessKey Secret, de la date, de la région et du nom du service.

  4. Calculez la signature.

    Signez la chaîne à signer avec la clé de signature via HMAC-SHA256, puis convertissez le résultat en une chaîne hexadécimale. Il s'agit de la signature finale.

image

Exemples de calcul de signature POST

  1. L'exemple Java suivant calcule une signature POST pour la politique ci-dessus.

    Identifiants AccessKey

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

    Le résultat suivant est renvoyé :

    signature:3908473f7dbfb79a102eaaa44ca1edec8d7058ce3bd1c624d59eb437463bd5d6

    Identifiants d'accès temporaires

    Lors de l'utilisation d'identifiants temporaires provenant de STS, obtenez un jeton de sécurité en appelant l'opération 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);
            }
        }
    }

    Le résultat suivant est renvoyé :

    signature:1e09438f7ad01af6b3e144b42c98929c68f8d090ce07f4c277b18d8b62d0aa02
  2. L'exemple Python suivant calcule une signature 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)

    Le résultat suivant est renvoyé :

    signature:9e85d56429245283b1aca5bc2dc31e0020b95ac2de9e9b81b496994db602ba1e