POST請求簽名(V4版本)
更新時間 2025-06-13 17:05:31
最近更新時間: 2025-06-13 17:05:31
分享文章
此文檔介紹通過POST請求上傳對象所需的V4版本簽名方法。
POST V4簽名說明
POST簽名是指使用POST方式上傳文件時,要求每個請求都必須附帶一個簽名(Signature)。與POST V2簽名方式不同的是,POST V4簽名是通過訪問密鑰(Secret Access Key)、當前時間以及Region等信息對一系列請求參數(上傳策略policy等)進行加密計算得到的。當請求發送時,會驗證簽名的合法性,只有簽名驗證成功的請求才會被接受,否則請求將被拒絕。
POST V4簽名表單獨有參數
POST V4簽名除了POST上傳對象中說明的公共表單元素外,會有一些獨有的表單元素:
| 參數 | 參數類型 | 說明 |
|---|---|---|
| x-amz-algorithm | String | 指定簽名的版本和算法,固定值為AWS4-HMAC-SHA256。 |
| x-amz-credential | String | 指明派生密鑰的參數集。格式:<AccessKeyId>/<date>/<region>/s3/aws4_request。 |
| x-amz-date | String | 請求的時間(遵循ISO 8601日期和時間標準)。格式:20241216T020211Z。 |
| x-amz-signature | String | 簽名認證信息。其值為通過HMAC-SHA256算法對Base64編碼后的policy字符串進行加密計算,然后所得的二進制哈希值轉換成十六進制的形式 |
Policy說明
Policy表單域是一種安全策略,若請求不包含Policy,則只能訪問public-read-write的Bucket, 當Bucket為非public-read-write或者提供了AccessKeyId(或Signature)表單域時,必須提供Policy表單域 。 Policy由JSON格式來定義,可以通過多項參數來限制上傳的相關操作,比如允許上傳的Bucket、Key前綴等。
其中policy中有兩個字段是必須的:
- expiration:指定policy的過期時間(ISO8601 GMT格式)。例如指定為2024-12-16T13:00:00.000Z,表示必須在2024年12月16日13點之前發起POST請求。
- conditions:指定POST請求表單域的合法值。
conditions表
| 參數 | 參數類型 | 必選 | 說明 | 匹配方式 | 示例 |
|---|---|---|---|---|---|
| bucket | String | 否 | 存儲桶名稱。 | bucket | {"bucket": "examplebucket"} |
| key | String | 否 | 上傳對象的名稱。 | eq、starts-with | ["eq", "$key", "ExampleObject"] |
| x-amz-algorithm | String | 是 | 指定簽名的版本和算法,固定值為AWS4-HMAC-SHA256。 | x-amz-algorithm | {"x-amz-algorithm": "AWS4-HMAC-SHA256"} |
| x-amz-credential | String | 是 | 指明派生密鑰的參數集。格式:<AccessKeyId>/<date>/<region>/s3/aws4_request。 |
x-amz-credential | {"x-amz-credential": "afwnu54***/20241216/us-east-1/s3/aws4_request"} |
| x-amz-date | String | 是 | 請求的時間(遵循ISO 8601日期和時間標準)。格式:20241216T020211Z。 | x-amz-date | {"x-amz-date": "20241216T020211Z"} |
| content-length-range | String | 否 | 上傳對象時的最小以及最大允許的大小,單位是字節。 | content-length-range | ["content-length-range", 1, 10] |
| success_action_status | String | 否 | 上傳成功后的返回狀態碼。 | eq、starts-with | ["eq", "$success_action_status", "201"] |
| content-type | String | 否 | 限制對象的文件類型。 | eq、starts-with | ["eq", "$content-type", "image/jpg"] |
| x-amz-security-token | String | 否 | 安全令牌。僅在通過STS構造POST簽名時需要該參數。可以通過調用STS服務的AssumeRole接口獲取安全令牌。 | x-amz-security-token | {"x-amz-security-token": "ek+NvIdz***"} |
| cache-control | String | 否 | 緩存控制。 | eq、starts-with | ["eq", "$cache-control", "no-cache"] |
conditions匹配方式表
| 匹配方式 | 說明 |
|---|---|
| eq | 精確匹配。比如 ["eq", "$key", "ExampleObject"],則表單域中指定key的值必須為ExampleObject:{"key": "ExampleObject"}。 |
| starts-with | 前綴匹配。比如 ["starts-with", "$key", "aaa/bbb"],則表單域中指定key的值必須以aaa/bbb開始:{"key": "aaa/bbb/ccc"}。 |
示例
{
"expiration": "2024-12-16T13:00:00.000Z",
"conditions": [
{"bucket": "testbucket"},
{"x-amz-algorithm": "AWS4-HMAC-SHA256"},
{"x-amz-credential": "afwnu54***/20241216/us-east-1/s3/aws4_request"},
{"x-amz-date": "20241216T020211Z"},
["content-length-range", 1, 10],
["eq", "$success_action_status", "201"],
["starts-with", "$key", "aaa/bbb/"],
["eq", "$content-type", "image/jpg"]
]
}
Signature形式
Hex(HmacSHA256(kSigning,Base64(PolicyJSON)))
簽名密鑰kSigning的生成規則
kDate=HmacSHA256("AWS4"+{SecretAccessKey}, {dateStamp})
kRegion=HmacSHA256(kDate, {region})
kService=HmacSHA256(kRegion, {service})
kSigning=HmacSHA256(kService, "aws4_request")
簽名步驟
- 第一步:創建utf-8編碼的policy
- 第二步:構造簽名字符串,在POST V4簽名中,StringToSign是policy的Base64編碼字符串
- 第三步:計算簽名密鑰,根據SecretAccessKey、dateStamp、region、service的值按照上述簽名密鑰的計算規則生成簽名密鑰kSigning
- 第四步:計算簽名Signature,生成最終的簽名時需要使用kSigning對StringToSign進行簽名,該簽名的計算方式為
Hex(HmacSHA256(kSigning,StringToSign)),所得到的十六進制字符串即為Signature
生成POST V4簽名參數代碼示例
這里提供Python示例代碼展示POST V4簽名的計算過程:
import hmac
import hashlib
import base64
import datetime
import json
def hmac_sha256(key, data):
return hmac.new(key, data.encode('utf-8'), hashlib.sha256).digest()
def compute_signature(current_date, region, service, secret_key, policy_string):
k_secret = ('AWS4' + secret_key).encode('utf-8')
k_date = hmac_sha256(k_secret, current_date)
k_region = hmac_sha256(k_date, region)
k_service = hmac_sha256(k_region, service)
k_signing = hmac_sha256(k_service, 'aws4_request')
signature = hmac_sha256(k_signing, policy_string)
return bytes_to_hex(signature)
def bytes_to_hex(byte_data):
return ''.join(f'{byte:02x}' for byte in byte_data)
def get_date(date):
return date.strftime('%Y%m%d')
def get_timestamp(date):
return date.strftime('%Y%m%dT%H%M%SZ')
def main():
access_key = "訪問密鑰ID"
secret_key = "私有訪問密鑰"
bucket = "testbuck"
key = "testobj"
region = "us-east-1"
service = "s3"
algorithm = "AWS4-HMAC-SHA256"
date = datetime.datetime.utcnow()
request_date = get_date(date)
date_stamp = get_timestamp(date)
credential = f"{access_key}/{request_date}/{region}/{service}/aws4_request"
# 構建 policy
policy_json = {
"expiration": "2024-12-16T13:00:00.000Z",
"conditions": [
{"bucket": bucket},
{"x-amz-algorithm": algorithm},
{"x-amz-credential": credential},
{"x-amz-date": date_stamp},
["starts-with", "$key", key]
]
}
# 創建簽名字符串
string_to_sign = base64.b64encode(json.dumps(policy_json).encode('utf-8')).decode('utf-8')
# 計算簽名
signature = compute_signature(request_date, region, service, secret_key, string_to_sign)
print("policy:", string_to_sign)
print("x-amz-algorithm:", algorithm)
print("x-amz-credential:", credential)
print("x-amz-date:", date_stamp)
print("x-amz-signature:", signature)
if __name__ == '__main__':
main()
輸出的結果:
policy: eyJleHBpcmF0aW9uIjogIjIwMjQtMTItMTZUMTM6MDA6MDAuMDAwWiIsICJjb25kaXRpb25zIjogW3siYnVja2V0IjogInRlc3RidWNrIn0sIHsieC1hbXotYWxnb3JpdGhtIjogIkFXUzQtSE1BQy1TSEEyNTYifSwgeyJ4LWFtei1jcmVkZW50aWFsIjogIlx1OGJiZlx1OTVlZVx1NWJjNlx1OTRhNUlELzIwMjQxMjE2L3VzLWVhc3QtMS9zMy9hd3M0X3JlcXVlc3QifSwgeyJ4LWFtei1kYXRlIjogIjIwMjQxMjE2VDAyMDIxMVoifSwgWyJzdGFydHMtd2l0aCIsICIka2V5IiwgInRlc3RvYmoiXV19
x-amz-algorithm: AWS4-HMAC-SHA256
x-amz-credential: 訪問密鑰ID/20241216/us-east-1/s3/aws4_request
x-amz-date: 20241216T020211Z
x-amz-signature: 65335e61c9c448fcc35283b12861f170f12f13ac03ef65037e44cb1f604048ca