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: |
x-oss-credential | String | Sí | Especifica el conjunto de parámetros para la clave derivada. El formato es el siguiente:
|
x-oss-date | String | Sí | Hora de la solicitud en formato ISO 8601. Ejemplo:
|
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.
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.000Zsignifica 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_requestAccessKeyId: 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-datepara 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 dondex-oss-dateha expirado para prevenir ataques de repetición.El valor de
x-oss-datefunciona comoTimeStampenStringToSign. Debe corresponder al mismo día queDateen la clave de firma y coincidir con el valor dex-oss-dateen 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
Proceso de cálculo de la firma
Cree una política codificada en UTF-8.
-
Construya la cadena a firmar.
Codifique la política en Base64. El resultado es la cadena a firmar.
-
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.
-
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.
Ejemplos de cálculo de firma POST
-
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:3908473f7dbfb79a102eaaa44ca1edec8d7058ce3bd1c624d59eb437463bd5d6Temporary 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 -
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