Postman调用S3预签名POST URL返回SignatureDoesNotMatch错误排查
S3预签名POST 403 SignatureDoesNotMatch问题解答
1. 调用方式正确性校验
你对预签名POST的核心调用逻辑是正确的,但存在几个容易踩的细节问题,符合以下要求才算完全正确的调用:
- form-data字段必须严格按照
createPresignedPost返回的fields顺序填充,所有返回字段不能遗漏、顺序不能调换,否则直接触发签名不匹配 file字段必须放在所有form字段的最后一位,不能插入到其他字段中间- 你的代码中配置了
Conditions: [["eq", "$Content-Type", "image/jpeg"]],因此请求必须携带Content-Type字段,且值必须完全等于image/jpeg,不能用image/jpg等别名,也不能加额外参数 - Postman中不要手动添加
Authorization、Content-Type等请求头,form-data格式的Content-Type会自动携带边界值,手动填写会覆盖自动生成的边界配置导致请求异常
2. 调试定位方法
- 首先打印S3返回的完整403响应头,提取
x-amz-signature-provided和x-amz-string-to-sign字段,和本地生成签名时的字符串做对比,差异点就是签名错误的原因 - 优先排除Postman的干扰,直接用Node.js代码发起测试请求,示例如下:
const FormData = require('form-data'); const fs = require('fs'); const axios = require('axios'); // 调用你封装的getSignedUrl方法获取签名结果 const { url, fields } = await getSignedUrl(); const form = new FormData(); // 按顺序插入所有返回的fields Object.entries(fields).forEach(([key, value]) => form.append(key, value)); // 插入和条件匹配的Content-Type form.append('Content-Type', 'image/jpeg'); // 最后插入文件 form.append('file', fs.readFileSync('./测试用的jpeg图片路径'), { filename: 'test.jpg', contentType: 'image/jpeg' }); await axios.post(url, form, { headers: form.getHeaders() });
- 存储桶日志本身有1-2小时的生成延迟,刚操作完看不到日志属于正常现象,不需要等日志输出,用上面的代码测试效率更高
3. 额外排查点
- 检查生成预签名的服务器系统时间,如果和AWS标准时间偏差超过15分钟,会直接导致签名失效
- 检查S3存储桶是否开启了KMS默认加密,如果开启需要在生成预签名的参数中补充KMS相关配置,或在Conditions中添加加密规则的匹配条件
- 确认预签名的有效期,
createPresignedPost默认有效期为3600秒,超过有效期后调用也会返回签名错误 - 确认生成预签名用的IAM账号有
s3:PutObject权限,且没有配置权限边界、会话策略等限制上传操作的规则 - 确认你没有修改返回的
fields中任何字段的值,包括policy、signature等字段,任何字符变动都会导致签名不匹配
内容的提问来源于stack exchange,提问作者Richbits
相关产品推荐
相关产品推荐

