You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

浏览器向Amazon S3上传图片时出现Signature mismatch问题排查

问题:向Amazon S3通过表单上传图片时出现Signature mismatch错误

我正尝试按照AWS官方文档中的步骤,从浏览器直接向Amazon S3上传图片。为编码Policy,我编写了如下Python 2.7代码片段:

import hmac 
import hashlib 
import base64 

def sign(key, msg): 
    return hmac.new(key, msg, hashlib.sha256).digest() 

post_policy = """{ 
    "expiration": "2018-12-30T12:00:00.000Z", 
    "conditions": [ 
        {"bucket": "<my_bucket>"}, 
        ["starts-with", "$key", "user/user1/"], 
        {"acl": "public-read"}, 
        {"success_action_redirect": "http://my_bucket.s3.amazonaws.com/successful_upload.html"}, 
        ["starts-with", "$Content-Type", "image/"], 
        {"x-amz-meta-uuid": "14365123651274"}, 
        {"x-amz-server-side-encryption": "AES256"}, 
        ["starts-with", "$x-amz-meta-tag", ""], 
        {"x-amz-credential": "<my-access-id>/20151229/us-east-2/s3/aws4_request"}, 
        {"x-amz-algorithm": "AWS4-HMAC-SHA256"}, 
        {"x-amz-date": "20181229T000000Z" } 
    ] 
}""" 

post_policy_utf8 = unicode(post_policy, "utf-8") 
base64_encoded_policy = base64.b64encode(post_policy_utf8) 

secret_key = '<my_secret_key>' 
signed_policy = sign(("AWS4" + base64_encoded_policy), secret_key) 
encoded_signed_policy = base64.b64encode(signed_policy) 

我的HTML表单如下:

<form action="http://<my_bucket>.s3.amazonaws.com/" method="post" enctype="multipart/form-data">
    Key to upload: <input type="input" name="key" value="user/user1/${filename}" /><br />
    <input type="hidden" name="acl" value="public-read" />
    <input type="hidden" name="success_action_redirect" value="http://<my_bucket>.s3.amazonaws.com/successful_upload.html" />
    Content-Type: <input type="input" name="Content-Type" value="image/jpeg" /><br />
    <input type="hidden" name="x-amz-meta-uuid" value="14365123651274" />
    <input type="hidden" name="x-amz-server-side-encryption" value="AES256" />
    <input type="text" name="X-Amz-Credential" value="AKIAJ5CZ54I742JS652A/20151229/us-east-2/s3/aws4_request" />
    <input type="text" name="X-Amz-Algorithm" value="AWS4-HMAC-SHA256" />
    <input type="text" name="X-Amz-Date" value="20181229T000000Z" />
    Tags for File: <input type="input" name="x-amz-meta-tag" value="" /><br />
    <input type="hidden" name="Policy" value='eyAiZXhwaXJhdGlvbiI6ICIyMDE4LTEyLTMwVDEyOjAwOjAwLjAwMFoiLAogICJjb25kaXRpb25zIjogWwogICAgeyJidWNrZXQiOiAiZmlsZS51cGxvYWQuZnJvbS5icm93c2VyIn0sCiAgICBbInN0YXJ0cy13aXRoIiwgIiRrZXkiLCAidXNlci91c2VyMS8iXSwKICAgIHsiYWNsIjogInB1YmxpYy1yZWFkIn0sCiAgICB7InN1Y2Nlc3NfYWN0aW9uX3JlZGlyZWN0IjogImh0dHA6Ly9maWxlLnVwbG9hZC5mcm9tLmJyb3dzZXIuczMuYW1hem9uYXdzLmNvbS9zdWNjZXNzZnVsX3VwbG9hZC5odG1sIn0sCiAgICBbInN0YXJ0cy13aXRoIiwgIiRDb250ZW50LVR5cGUiLCAiaW1hZ2UvIl0sCiAgICB7IngtYW16LW1ldGEtdXVpZCI6ICIxNDM2NTEyMzY1MTI3NCJ9LAogICAgeyJ4LWFtei1zZXJ2ZXItc2lkZS1lbmNyeXB0aW9uIjogIkFFUzI1NiJ9LAogICAgWyJzdGFydHMtd2l0aCIsICIkeC1hbXotbWV0YS10YWciLCAiIl0sCiAgICAKICAgIHsieC1hbXotY3JlZGVudGlhbCI6ICJBS0lBSjVDWjU0STc0MkpTNjUyQS8yMDE1MTIyOS91cy1lYXN0LTIvczMvYXdzNF9yZXF1ZXN0In0sCiAgICB7IngtYW16LWFsZ29yaXRobSI6ICJBV1M0LUhNQUMtU0hBMjU2In0sCiAgICB7IngtYW16LWRhdGUiOiAiMjAxODEyMjlUMDAwMDAwWiIgfQogIF0KfQ==' />
    <input type="hidden" name="X-Amz-Signature" value="ZG0xBgY5y1Fin0D7kKAO9tuqGntG1Ptw4GDaiLvfvGU=" />
    File: <input type="file" name="file" />
    <br />
    <!-- The elements after this will be ignored -->
    <input type="submit" name="submit" value="Upload to Amazon S3" />
</form>

Policy的Base64值和签名均由上述Python 2.7代码生成,但提交表单时AWS提示Signature mismatch。请问问题出在哪里,该如何修正?


问题分析与解决方案

你遇到的签名不匹配问题主要来自三个核心错误,下面逐一说明并给出修正方案:

1. SigV4签名密钥生成逻辑错误

AWS SigV4的签名流程不是直接用AWS4 + base64编码的policy去和密钥签名,而是需要分层推导签名密钥:

  • 第一步:用日期(格式YYYYMMDD)和AWS4<你的秘钥>生成第一个HMAC哈希
  • 第二步:用区域(比如us-east-2)和第一步的结果生成第二个哈希
  • 第三步:用服务名称s3和第二步的结果生成第三个哈希
  • 第四步:用aws4_request和第三步的结果生成最终的签名密钥
  • 最后用这个签名密钥去签名base64编码后的policy

2. Policy中的日期与Credential日期不一致

你的Policy里x-amz-date是20181229T000000Z,但x-amz-credential里的日期是20151229,这两个日期必须完全一致(格式YYYYMMDD部分要匹配),否则AWS会判定签名无效。

3. Python编码处理错误

在Python 2.7中,unicode(post_policy, "utf-8")的写法是错误的:如果post_policy本身是字符串(str类型),应该用post_policy.encode('utf-8')来转成UTF-8编码的字节流,否则会导致policy的编码不正确,进而签名不匹配。


修正后的Python 2.7代码

import hmac
import hashlib
import base64

def sign(key, msg):
    return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()

def get_signature_key(secret_key, date_stamp, region_name, service_name):
    # 按照SigV4步骤生成签名密钥
    k_date = sign(('AWS4' + secret_key).encode('utf-8'), date_stamp)
    k_region = sign(k_date, region_name)
    k_service = sign(k_region, service_name)
    k_signing = sign(k_service, 'aws4_request')
    return k_signing

# 统一日期(确保和policy里的日期一致)
date_stamp = '20181229'
amz_date = '20181229T000000Z'
access_id = '<my-access-id>'
bucket_name = '<my_bucket>'
secret_key = '<my_secret_key>'
region = 'us-east-2'

post_policy = """{{
    "expiration": "2018-12-30T12:00:00.000Z",
    "conditions": [
        {{"bucket": "{bucket}"}},
        ["starts-with", "$key", "user/user1/"],
        {{"acl": "public-read"}},
        {{"success_action_redirect": "http://{bucket}.s3.amazonaws.com/successful_upload.html"}},
        ["starts-with", "$Content-Type", "image/"],
        {{"x-amz-meta-uuid": "14365123651274"}},
        {{"x-amz-server-side-encryption": "AES256"}},
        ["starts-with", "$x-amz-meta-tag", ""],
        {{"x-amz-credential": "{access_id}/{date_stamp}/{region}/s3/aws4_request"}},
        {{"x-amz-algorithm": "AWS4-HMAC-SHA256"}},
        {{"x-amz-date": "{amz_date}"}}
    ]
}}""".format(bucket=bucket_name, access_id=access_id, date_stamp=date_stamp, region=region, amz_date=amz_date)

# 正确处理编码:转成UTF-8字节流
post_policy_utf8 = post_policy.encode('utf-8')
base64_encoded_policy = base64.b64encode(post_policy_utf8)

# 生成签名密钥并签名policy
signing_key = get_signature_key(secret_key, date_stamp, region, 's3')
signed_policy = hmac.new(signing_key, base64_encoded_policy, hashlib.sha256).digest()
encoded_signed_policy = base64.b64encode(signed_policy)

# 打印结果,用于填充到HTML表单
print("Policy Base64:", base64_encoded_policy)
print("Signature:", encoded_signed_policy)

修正后的HTML表单要点

  1. 确保X-Amz-Credential中的日期部分是20181229,和X-Amz-Date的日期一致
  2. 替换Policy和X-Amz-Signature的值为修正后代码输出的结果
  3. 确认表单中的所有隐藏字段值和Policy里的conditions完全匹配(比如acl、x-amz-meta-uuid等)

内容的提问来源于stack exchange,提问作者Sujay DSa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:22:38