S3预签名PUT URL上传图片遇SignatureDoesNotMatch错误求助
问题
我需要生成预签名PUT URL以向S3存储桶上传文件,当Content-Type为text/plain时,文本文件上传正常。但上传图片(如dummy.png)时出现SignatureDoesNotMatch错误。
输入参数
const bucketParameter: PutObjectCommandInput = { Bucket: "myBucket", Key: "dummy.png", Body: Buffer.from("BODY", "utf-8"), ContentType: "image/png", };
代码实现
import { GetObjectCommand, PutObjectCommand, PutObjectCommandInput, S3Client } from "@aws-sdk/client-s3"; import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; const AWS = require("aws-sdk"); AWS.config.update({ accessKeyId: "myAccessKey", secretAccessKey: "mySecretKey", region: "myRegion", }); export async function getPresignedPutURL(bucketParameter: PutObjectCommandInput, region: string) { const s3Client = new S3Client({ region: region }); try { const command = new PutObjectCommand(bucketParameter); const signedUrl = await getSignedUrl(s3Client, command, { expiresIn: 3600, }); return signedUrl; } catch (err) { throw new Error("Error creating presigned PUT URL" + err.message); } }
上传请求头
Accept: */* User-Agent: Thunder Client (https://www.thunderclient.com) Content-Type: image/png
错误信息
<?xml version="1.0" encoding="UTF-8"?> <Error> <Code>SignatureDoesNotMatch</Code> <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message> <AWSAccessKeyId>AKIATFE5YPEBOFPZJYRN</AWSAccessKeyId> <StringToSign>AWS4-HMAC-SHA256 20220818T085341Z 20220818/us-east-1/s3/aws4_request 8fcfeba678fa30bdf6ce03595ecb6e80b5aa5429aa0b5b0c7820489113871295</StringToSign> <SignatureProvided>606187f7b354fc07df7e7cb0967a71f701c7df32c50393613e4124d95bce950f</SignatureProvided> <StringToSignBytes>41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 0a 32 30 32 32 30 38 31 38 54 30 38 35 33 34 31 5a 0a 32 30 32 32 30 38 31 38 2f 75 73 2d 65 61 73 74 2d 31 2f 73 33 2f 61 77 73 34 5f 72 65 71 75 65 73 74 0a 38 66 63 66 65 62 61 36 37 38 66 61 33 30 62 64 66 36 63 65 30 33 35 39 35 65 63 62 36 65 38 30 62 35 61 61 35 34 32 39 61 61 30 62 35 62 30 63 37 38 32 30 34 38 39 31 31 33 38 37 31 32 39 35</StringToSignBytes> <CanonicalRequest>PUT /dummy.png X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIATFE5YPEBOFPZJYRN%2F20220818%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20220818T085341Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=content-length%3Bhost&x-id=PutObject content-length:17663 host:eu-central-1-radix-iflair.s3.us-east-1.amazonaws.com content-length;host UNSIGNED-PAYLOAD</CanonicalRequest> <CanonicalRequestBytes>50 55 54 0a 2f 64 75 6d 6d 79 2e 70 6e 67 0a 58 2d 41 6d 7a 2d 41 6c 67 6f 72 69 74 68 6d 3d 41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 26 58 2d 41 6d 7a 2d 43 6f 6e 74 65 6e 74 2d 53 68 61 32 35 36 3d 55 4e 53 49 47 4e 45 44 2d 50 41 59 4c 4f 41 44 26 58 2d 41 6d 7a 2d 43 72 65 64 65 6e 74 69 61 6c 3d 41 4b 49 41 54 46 45 35 59 50 45 42 4f 46 50 5a 4a 59 52 4e 25 32 46 32 30 32 32 30 38 31 38 25 32 46 75 73 2d 65 61 73 74 2d 31 25 32 46 73 33 25 32 46 61 77 73 34 5f 72 65 71 75 65 73 74 26 58 2d 41 6d 7a 2d 44 61 74 65 3d 32 30 32 32 30 38 31 38 54 30 38 35 33 34 31 5a 26 58 2d 41 6d 7a 2d 45 78 70 69 72 65 73 3d 33 36 30 30 26 58 2d 41 6d 7a 2d 53 69 67 6e 65 64 48 65 61 64 65 72 73 3d 63 6f 6e 74 65 6e 74 2d 6c 65 6e 67 74 68 25 33 42 68 6f 73 74 26 78 2d 69 64 3d 50 75 74 4f 62 6a 65 63 74 0a 63 6f 6e 74 65 6e 74 2d 6c 65 6e 67 74 68 3a 31 37 36 36 33 0a 68 6f 73 74 3a 65 75 2d 63 65 6e 74 72 61 6c 2d 31 2d 72 61 64 69 78 2d 69 66 6c 61 69 72 2e 73 33 2e 75 73 2d 65 61 73 74 2d 31 2e 61 6d 61 7a 6f 6e 61 77 73 2e 63 6f 6d 0a 0a 63 6f 6e 74 65 6e 74 2d 6c 65 6e 67 74 68 3b 68 6f 73 74 0a 55 4e 53 49 47 4e 45 44 2d 50 41 59 4c 4f 41 44</CanonicalRequestBytes> <RequestId>TP7WQ2EVDH41F2V3</RequestId> <HostId>brjgBeKuLLcc7pzrrBMPRNtVp2jO/irnMRTyXPwDm9tKUi2aa/FuIG5AJcYVvcbQs7y3jyAIpJ4=</HostId> </Error>
原因与解决方案
问题根源
生成预签名PUT URL时,你在bucketParameter中指定了固定的Body: Buffer.from("BODY", "utf-8"),AWS SDK会基于这个Body的内容(或其长度、哈希值)计算签名。但实际上传时,你发送的是真实PNG文件的二进制内容,长度(17663字节)和内容都与生成URL时指定的Body完全不符,导致S3验证签名时不匹配。
而text/plain场景下能正常上传,是因为你实际上传的内容和生成URL时指定的BODY文本一致,签名验证通过。
解决方案
生成预签名PUT URL时,不要在PutObjectCommandInput中传入Body参数。预签名PUT URL的设计目的是让客户端上传任意符合要求的内容,只需指定Bucket、Key、ContentType这些必要元数据即可。修改后的输入参数如下:
const bucketParameter: PutObjectCommandInput = { Bucket: "myBucket", Key: "dummy.png", ContentType: "image/png", // 移除Body参数 };
这样生成的预签名URL不会绑定固定的Body内容,客户端上传真实图片二进制数据时,签名验证就能正常通过。
内容的提问来源于stack exchange,提问作者Gernot Kovar
相关产品推荐
相关产品推荐

