AWS预签名POST请求签名不匹配及签名过短问题求助
尝试实现S3前端直传功能时,始终收到AWS错误:
The request signature we calculated does not match the signature you provided. Check your key and signing method.,发现生成的签名比官方示例短,已验证AWS凭证有效(服务器直传S3成功),提供后端Python代码和前端HTML代码,请求排查原因。
后端Python代码
def annotate(): try: if request.method == 'POST': pass unique_filename = str(uuid.uuid4()) file_name_prefix = f"folder_name/{unique_filename}~" object_name = file_name_prefix+"${filename}" s3_policy_conditions = [ {"bucket": S3_BUCKET_NAME}, {"acl": "private"}, {"success_action_redirect": "www.success.html"}, {"key":object_name} ] fields = {"key": file_name_prefix+"${filename}", "acl": "private"} # Generate presigned post request encoded_policy = s3.generate_presigned_post( Bucket=S3_BUCKET_NAME, Key=object_name, Fields=fields, Conditions=s3_policy_conditions, ExpiresIn=120 # 2 minutes ) print(encoded_policy) return render_template('annotate.html',data=encoded_policy) except Exception as e: # Handle errors appropriately error_response = { 'code': 500, 'status': 'error', 'message': str(e) } return jsonify(error_response)
前端HTML代码
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <h1>Upload VCF File</h1> <form id="upload_form" action="{{ data['url'] }}" method="post" enctype="multipart/form-data" > <input type="hidden" name="key" value="{{ data['fields']['key']~filename }}"> <input type="hidden" name="acl" value="private"> <input type="hidden" name="success_action_redirect" value="vkodagi-hw3.mpcs-cc.com:5000/annotate/files" /> <input type="hidden" name="AWSAccessKeyId" value="{{ data['fields']['AWSAccessKeyId'] }}" /> <input type="hidden" name="policy" value="{{ data['fields']['policy'] | tojson}}" /> <input type="hidden" name="signature" value="{{ data['fields']['signature']}}" /> Select input file: <input id="upload_file" type="file" name="file" /> <input type="submit" value="Upload Input File" /> </form> </body> </html>
问题排查与修复方案
Policy字段重复序列化
generate_presigned_post返回的policy已经是Base64编码后的字符串,前端使用| tojson过滤器会给它额外添加引号,导致policy值失真,签名验证失败。
修复:将前端的policy字段改为:<input type="hidden" name="policy" value="{{ data['fields']['policy'] }}" />Key字段前后端不匹配
后端生成的key规则是folder_name/{uuid}~${filename},但前端手动拼接~filename后,实际提交的key变成folder_name/{uuid}~${filename}~filename,与policy中的key条件冲突。
修复:直接使用后端返回的key值,S3会自动替换${filename}为实际文件名:<input type="hidden" name="key" value="{{ data['fields']['key'] }}">Success Action Redirect条件不一致
后端policy中定义的跳转地址是www.success.html,但前端手动设置为vkodagi-hw3.mpcs-cc.com:5000/annotate/files,违反了policy的约束条件。
修复:删除前端手动添加的该字段,改用后端返回的值(需确保后端fields中包含该字段),或统一前后端的跳转地址。ACL字段冗余定义
后端已经在返回的fields中包含了acl字段,前端重复定义可能引发潜在冲突。
修复:改用后端返回的acl值:<input type="hidden" name="acl" value="{{ data['fields']['acl'] }}" />
内容的提问来源于stack exchange,提问作者unknownCoder

