PostObject リクエストの有効性とセキュリティを確保するために、PostObject リクエストに署名を含める必要があります。PostObject リクエストの V4 署名は、AccessKey シークレット、現在の時刻、およびリージョンに基づいて、ポリシーや有効期限を含む一連のリクエストパラメーターを暗号化することで計算されます。アプリケーションサーバーが署名を生成した後、アプリケーションサーバーは署名とアップロードポリシーを含む情報をクライアントに返します。クライアントはその情報を使用してアップロードリクエストを作成します。OSS はアップロードリクエストを受信した後、署名の有効性を検証します。有効な署名を含むリクエストのみが許可されます。署名検証に失敗したリクエストは拒否されます。
PostObject リクエストの署名
データセキュリティを強化するために、PostObject リクエストは V4 署名アルゴリズムを統合しています。フォーム要素とポリシーフォームフィールドは、PostObject リクエストの有効性とセキュリティを確保する上で重要な役割を果たします。
フォーム要素
フォームは、アップロードするオブジェクトとそのメタデータに関する情報を渡すために、PostObject リクエストで実際に運ばれるフィールドの集合です。次の表は、PostObject リクエストの V4 署名に固有のフォーム要素について説明しています。共通のフォーム要素の詳細については、「フォーム要素」をご参照ください。
要素 | タイプ | 必須 | 説明 |
x-oss-signature-version | 文字列 | はい | 署名バージョンと署名の計算に使用されるアルゴリズム。値を OSS4-HMAC-SHA256 に設定します。 |
x-oss-credential | 文字列 | はい | 署名の計算に使用できる資格情報。フォーマット:
|
x-oss-date | 文字列 | はい | リクエストが開始された時刻。時刻は ISO 8601 標準に従う必要があります。例:
|
x-oss-signature | 文字列 | はい | 署名検証に使用される記述。値は、Base64 エンコードされたポリシー文字列を HMAC-SHA256 を使用して暗号化し、HMAC-SHA256 を使用して取得したバイナリハッシュを 16 進数形式に変換することで計算されます。 |
policy
PostObject リクエストの policy フォームフィールドは、HTML フォームを使用してオブジェクトをアップロードするために開始する PostObject リクエストの有効期限と条件を指定するために使用されます。policy フォームフィールドの値は、オブジェクトをアップロードするバケット名、オブジェクト名のプレフィックス、リクエストの有効期間、許可される HTTP メソッド、オブジェクトのサイズとコンテンツなど、複数のパラメーターを指定することで PostObject リクエストを制限する JSON 文字列です。
policy フォームフィールドには、expiration パラメーターと conditions パラメーターを含める必要があります。Conditions パラメーターの次のフィールドには、x-oss-security-token パラメーターなどのオプションパラメーターが含まれています。これは、セキュリティトークンを使用して PostObject リクエストの署名を作成する場合にのみ必要です。AccessKey ペアを使用して PostObject リクエストの署名を作成する場合、x-oss-security-token パラメーターは不要です。
{
"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"]]
]
}policy フォームフィールドの必須パラメーター
expiration
expiration パラメーターは、リクエストの有効期限を指定します。時刻は ISO 8601 標準に従う必要があり、GMT である必要があります。たとえば、
2023-12-03T13:00:00.000Zは、PostObject リクエストを 2023 年 12 月 3 日 13:00 より前に送信する必要があることを指定します。conditions
conditions パラメーターは、PostObject リクエストのフォームフィールドの有効な値を指定するリストです。
パラメーター
タイプ
必須
説明
一致モード
bucket
文字列
いいえ
バケットの名前。
bucket
x-oss-signature-version
文字列
はい
署名バージョンと署名の計算に使用されるアルゴリズム。値を OSS4-HMAC-SHA256 に設定します。
x-oss-signature-version
x-oss-credential
文字列
はい
署名の計算に使用できる資格情報。フォーマット:
<AccessKeyId>/<date>/<region>/oss/aliyun_v4_requestAccessKeyId:AccessKey ペアの AccessKey ID。
date:リクエストが開始された日付。
region:アクセスするバケットが配置されている Alibaba Cloud リージョンの ID。例:cn-hangzhou。
oss:リクエストされたサービスの名前。値を oss に設定します。
aliyun_v4_request:リクエストの署名バージョンの説明。値を aliyun_v4_request に設定します。
x-oss-credential
x-oss-security-token
文字列
いいえ
このパラメーターは、セキュリティトークンを使用して PostObject リクエストの署名を作成する場合にのみ必要です。STS の AssumeRole 操作を呼び出すことで、セキュリティトークンを取得できます。
x-oss-security-token
x-oss-date
文字列
はい
リクエストが開始された時刻。時刻は ISO 8601 標準に従う必要があります。例:
20231203T121212Z。リクエスト開始後最大 15 分のオフセットが許容されます。したがって、サーバーがリクエストを受信する時刻は、
x-oss-dateで指定された時刻より最大 15 分遅れる可能性があります。これにより、ネットワーク伝送の遅延やクライアントとサーバー間の時差が存在する場合でも、リクエストが想定どおりに処理されることが保証されます。リクエストの有効期間は最大 7 日間です。
x-oss-dateで指定された時刻の 7 日後、OSS はリクエストを拒否し、エラーが報告されます。これにより、リクエストの適時性とセキュリティが確保され、期限切れまたは署名済みリクエストの悪意のある送信を防ぎます。x-oss-dateで指定された時刻は、署名対象文字列のタイムスタンプとして使用されます。値は、派生キーの date フィールドの値、およびポリシーフォームフィールドの x-oss-date フィールドの値と同じである必要があります。
x-oss-date
content-length-range
文字列
いいえ
アップロードするオブジェクトの許容される最小サイズと最大サイズ。単位:バイト。
content-length-range
success_action_status
文字列
いいえ
オブジェクトのアップロード後に返される HTTP ステータスコード。
eq、starts-with、in、および not-in
key
文字列
いいえ
アップロードするオブジェクトの名前。
eq、starts-with、in、および not-in
content-type
文字列
いいえ
アップロードするオブジェクトのタイプ。
eq、starts-with、in、および not-in
cache-control
文字列
いいえ
オブジェクトのキャッシュ動作。
eq、starts-with、in、および not-in
署名計算プロセス
UTF-8 エンコードされたポリシーを作成します。
署名対象文字列を作成します。
ポリシーを Base64 エンコードして、署名対象文字列として安全に送信できる文字列を生成します。
署名キーを計算します。
HMAC-SHA256 を使用して署名対象文字列を暗号化します。アカウントの派生キーを HMAC-SHA256 を使用するキーとして使用します。
署名を計算します。
HMAC-SHA256 を使用して計算されたバイナリハッシュを 16 進数文字列に変換します。取得した 16 進数文字列は、リクエストの整合性と有効性を検証するために使用される署名です。
例
次のサンプルコードは、OSS SDK for Java を使用して、上記のポリシーを使用して PostObject リクエストの V4 署名を計算する方法の例を示しています。
アクセスキー ( AK ) またはシークレットキー ( SK ) を使用する
import com.aliyun.oss.common.utils.BinaryUtil; import org.apache.commons.codec.binary.Base64; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; public class Demo { public static void main(String[] args) throws Exception { // サンプルコードを実行する前に、OSS_ACCESS_KEY_ID 環境変数と OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。 String accesskeyid = System.getenv().get("OSS_ACCESS_KEY_ID"); String accesskeysecret = System.getenv().get("OSS_ACCESS_KEY_SECRET"); // 手順 1:ポリシーを作成する。 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"); // この変数を実際の AccessKey ID に置き換えてください。 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); // 手順 2:署名対象文字列を作成する。 String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes())); System.out.println(stringToSign) // 手順 3:署名キーを計算する。 byte[] dateKey = hmacsha256(("aliyun_v4" + accesskeysecret).getBytes(), "20231203"); byte[] dateRegionKey = hmacsha256(dateKey, "cn-hangzhou"); byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss"); byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request"); // 手順 4:署名を計算する。 byte[] result = hmacsha256(signingKey, stringToSign); String signature = BinaryUtil.toHex(result); System.out.println("signature:" + signature); } public static byte[] hmacsha256(byte[] key, String data) { try { // SecretKeySpec を初期化し、アルゴリズムを HMAC-SHA256 に設定し、指定されたキーを使用します。 SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256"); // Mac インスタンスを取得し、getInstance メソッドを使用してアルゴリズムを HMAC-SHA256 に設定します。 Mac mac = Mac.getInstance("HmacSHA256"); // キーを使用して Mac インスタンスを初期化します。 mac.init(secretKeySpec); // HMAC 値を計算します。doFinal メソッドを使用して計算対象のデータを受信し、計算結果を配列として返します。 byte[] hmacBytes = mac.doFinal(data.getBytes()); return hmacBytes; } catch (Exception e) { throw new RuntimeException("HMAC-SHA256 の計算に失敗しました", e); } } }サンプルレスポンス:
signature:3908473f7dbfb79a102eaaa44ca1edec8d7058ce3bd1c624d59eb437463bd5d6一時的なアクセス認証情報を使用する
一時的なアクセス認証情報を使用して PostObject リクエストの署名を計算する場合、STS の 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 { // STSClient インスタンスを初期化する。 public static com.aliyun.sts20150401.Client createStsClient() throws Exception { com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config() // OSS_ACCESS_KEY_ID 環境変数が設定されていることを確認してください。 .setAccessKeyId(System.getenv("OSS_ACCESS_KEY_ID")) // OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。 .setAccessKeySecret(System.getenv("OSS_ACCESS_KEY_SECRET")); // エンドポイント config.endpoint = "sts.cn-hangzhou.aliyuncs.com"; return new com.aliyun.sts20150401.Client(config); } // 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() // OSS_STS_ROLE_ARN 環境変数が設定されていることを確認してください。 .setRoleArn(System.getenv("OSS_STS_ROLE_ARN")) .setRoleSessionName("role_session_name");// セッション名を指定します。 com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions(); try { // 必要に応じて、API 操作のレスポンスを表示するための独自のコードを記述してください。 AssumeRoleResponse response = client.assumeRoleWithOptions(assumeRoleRequest, runtime); // 後続の操作に必要な AccessKey ID、AccessKey シークレット、および STS トークンは、credentials に含まれています。 return response.body.credentials; } catch (TeaException error) { // 実際のビジネスシナリオでは例外を慎重に処理し、プロジェクトで例外を無視しないでください。この例に表示されるエラーメッセージは参考用です。 // エラーメッセージ。 System.out.println(error.getMessage()); // トラブルシューティング用の 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); // 実際のビジネスシナリオでは例外を慎重に処理し、プロジェクトで例外を無視しないでください。この例に表示されるエラーメッセージは参考用です。 // エラーメッセージ。 System.out.println(error.getMessage()); // トラブルシューティング用の 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; // 手順 1:ポリシーを作成する。 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); // 手順 2:署名対象文字列を作成する。 String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes())); // 手順 3:署名キーを計算する。 byte[] dateKey = hmacsha256(("aliyun_v4" + accesskeysecret).getBytes(), "20231203"); byte[] dateRegionKey = hmacsha256(dateKey, "cn-hangzhou"); byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss"); byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request"); // 手順 4:署名を計算する。 byte[] result = hmacsha256(signingKey, stringToSign); String signature = BinaryUtil.toHex(result); System.out.println("signature:" + signature); } public static byte[] hmacsha256(byte[] key, String data) { try { // SecretKeySpec を初期化し、アルゴリズムを HMAC-SHA256 に設定し、指定されたキーを使用します。 SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256"); // Mac インスタンスを取得し、getInstance メソッドを使用してアルゴリズムを HMAC-SHA256 に設定します。 Mac mac = Mac.getInstance("HmacSHA256"); // キーを使用して Mac インスタンスを初期化します。 mac.init(secretKeySpec); // HMAC 値を計算します。doFinal メソッドを使用して計算対象のデータを受信し、計算結果を配列として返します。 byte[] hmacBytes = mac.doFinal(data.getBytes()); return hmacBytes; } catch (Exception e) { throw new RuntimeException("HMAC-SHA256 の計算に失敗しました", e); } } }サンプルレスポンス:
signature:1e09438f7ad01af6b3e144b42c98929c68f8d090ce07f4c277b18d8b62d0aa02次のサンプルコードは、OSS SDK for Python を使用して PostObject リクエストの V4 署名を計算する方法の例を示しています。
import base64 import hmac import hashlib import os def hmac_sha256(key, data): return hmac.new(key, data.encode('utf-8'), hashlib.sha256).digest() # 環境変数から AccessKey ID と AccessKey シークレットを取得します。 accesskeyid = os.getenv('OSS_ACCESS_KEY_ID') accesskeysecret = os.getenv('OSS_ACCESS_KEY_SECRET') # AccessKey ID を表示します。 print(accesskeyid) # 環境変数が取得されているかどうかを確認します。 if not accesskeyid or not accesskeysecret: raise ValueError("必要な環境変数が見つかりません:OSS_ACCESS_KEY_ID または OSS_ACCESS_KEY_SECRET") # ポリシーを作成します。 policy = '''{ "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"}, // accesskeyid を実際のアクセスキー ID に置き換えてください。 {"x-oss-date": "20241105T065000Z"} ] }''' # ポリシーを出力します。 print(policy) # 署名対象文字列を計算します。 string_to_sign = base64.b64encode(policy.encode('utf-8')).decode('utf-8') print(string_to_sign) # 署名キーを計算します。 date_key = hmac_sha256(f"aliyun_v4{accesskeysecret}".encode('utf-8'), "20241105") date_region_key = hmac_sha256(date_key, "cn-beijing") date_region_service_key = hmac_sha256(date_region_key, "oss") signing_key = hmac_sha256(date_region_service_key, "aliyun_v4_request") # 署名を計算します。 result = hmac_sha256(signing_key, string_to_sign) signature = result.hex() print("signature:", signature)サンプルレスポンス:
signature:9e85d56429245283b1aca5bc2dc31e0020b95ac2de9e9b81b496994db602ba1e