使用Lambda生成的预签名URL上传Amazon S3时遇403签名不匹配错误
使用Lambda生成的S3预签名URL上传文件时出现403 Forbidden(SignatureDoesNotMatch)错误排查
问题场景
通过Lambda生成S3预签名PUT URL,返回给用户后,用户使用Postman调用该URL上传文件时触发403 Forbidden错误,错误详情如下:
return (<Code>SignatureDoesNotMatch</Code> )return (<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message> )
已完成的配置与代码实现
配置项
- 已为Lambda执行角色附加S3全访问权限策略
- Lambda部署在VPC私有网络中
- S3 Bucket已配置允许Lambda访问
代码实现
方式一:使用getSignedUrl生成预签名URL
import { getSignedUrl } from '@aws-sdk/s3-request-presigner' import { PutObjectCommandInput, S3Client, PutObjectCommand } from '@aws-sdk/client-s3' const Bucket = process.env.BUCKET_NAME! const client = new S3Client({ region: process.env.AWS_REGION!, }) const params: PutObjectCommandInput = { Bucket, Key: `xxxxx/yyyyy` } return await getSignedUrl(client, new PutObjectCommand(params), { expiresIn: 3000 })
方式二:手动实例化S3RequestPresigner生成预签名URL
import { S3RequestPresigner } from '@aws-sdk/s3-request-presigner' import { parseUrl } from '@aws-sdk/url-parser' import { Hash } from '@aws-sdk/hash-node' import { HttpRequest } from '@aws-sdk/protocol-http' import { S3Client } from '@aws-sdk/client-s3' const Bucket = process.env.BUCKET_NAME const client = new S3Client({ region: process.env.AWS_REGION!, }) const s3ObjectUrl = parseUrl(`https://${Bucket}.s3.${process.env.AWS_REGION}.amazonaws.com/xxxxx/yyyyy`) const presigner = new S3RequestPresigner({ credentials: { accessKeyId: process.env.AWS_ACCESS_KEY_ID!, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY! }, region: process.env.AWS_REGION!, sha256: Hash.bind(null, 'sha256'), }) return await presigner.presign(new HttpRequest({ ...s3ObjectUrl, method: 'PUT' }), { expiresIn: 3000 })
排查思路
1. 确保请求参数完全匹配
- 上传时必须使用PUT方法,与预签名生成时的请求方法一致
- 上传的对象Key必须和预签名中指定的
xxxxx/yyyyy完全一致,包括大小写、路径格式 - 如果上传时设置了
Content-Type,预签名生成时必须在PutObjectCommand参数中添加相同的Content-Type字段,否则签名验证会失败
2. 检查Lambda的VPC网络连通性
- 如果Lambda在私有子网:
- 要么配置NAT网关,确保Lambda能访问公网S3端点
- 要么配置S3网关端点(Gateway Endpoint),并确认VPC路由表已添加指向该端点的路由,同时端点策略允许Lambda角色访问目标Bucket
- 网络不通会导致预签名生成时的凭证或签名逻辑异常,间接引发签名不匹配
3. 规范凭证使用与SDK版本
- 方式二中硬编码AWS凭证的做法不推荐,改用Lambda执行角色的临时凭证(即方式一的实现),避免硬编码凭证过期、权限不符或泄露
- 确保所有
@aws-sdk相关依赖包版本一致,版本差异可能导致签名算法不兼容
4. 验证S3 Bucket策略与权限
- 检查Bucket策略是否明确允许
s3:PutObject操作,资源路径需匹配arn:aws:s3:::${Bucket}/xxxxx/yyyyy - 确认Lambda执行角色的权限策略中,包含对目标Bucket的
s3:PutObject权限(即使是全访问策略,也需确认资源范围覆盖目标对象路径)
5. 检查时间同步
- 预签名URL的签名依赖精准时间,如果Lambda所在环境的系统时间与AWS服务器时间偏差超过5分钟,会触发签名验证失败,需确认Lambda的时间同步正常
内容的提问来源于stack exchange,提问作者Take
相关产品推荐
相关产品推荐

