使用JavaScript调用AWS S3 REST API遇SignatureDoesNotMatch错误求助
AWS S3 SignatureDoesNotMatch 错误排查
我用Node.js编写了通过REST API发送GET请求的代码,使用Access Key和Secret Key生成签名,但遇到了SignatureDoesNotMatch错误。相同的请求头在Postman中可以正常运行,以下是我的代码及错误信息,恳请帮忙定位问题:
var https = require('https'); var crypto = require('crypto'); function sign(key, message) { return crypto.createHmac('sha256', key).update(message).digest(); } function getSignatureKey(key, dateStamp, regionName, serviceName) { kDate = sign('AWS4' + key, dateStamp); kRegion = sign(kDate, regionName); kService = sign(kRegion, serviceName); kSigning = sign(kService, 'aws4_request'); return kSigning; } // values retrieved from Cognito Federation accessKey = "MYACCESSKEY"; secretKey = "my/sharedkey"; region = "us-east-1"; serviceName = "s3"; // ex 20180518T210317Z var now = new Date(); amzdate = now.toJSON().replace(/[-:]/g, "").replace(/\.[0-9]*/, ""); datestamp = now.toJSON().replace(/-/g, "").replace(/T.*/, ""); // prepare to send an HTTP request to https://your-api-gateway.execute-api.eu-west-2.amazonaws.com/stage/secure/endpoint apiMethod = "GET"; apiHost = "my_host_name.com"; apiEndpoint="/bucket_name/object_name"; apiQueryString = ""; canonicalHeaders = "host:" + apiHost + "\nx-amz-date:" + amzdate +"\n"; //"\nx-amz-security-token:" + sessionToken + "\n" signedHeaders = "host;x-amz-date;"; payloadHash = crypto.createHash('sha256').update('').digest('hex'); canonicalRequest = apiMethod + "\n" + apiEndpoint + "\n" + apiQueryString + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + payloadHash; console.log('preparing to invoke canonical request:'); console.log(canonicalRequest); // ************* TASK 2: CREATE THE STRING TO SIGN************* // Match the algorithm to the hashing algorithm you use, either SHA-1 or // SHA-256 (recommended) algorithm = 'AWS4-HMAC-SHA256'; credentialScope = datestamp + '/' + region + '/' + serviceName + '/' + 'aws4_request'; stringToSign = algorithm + '\n' + amzdate + '\n' + credentialScope + '\n' + crypto.createHash('sha256').update(canonicalRequest).digest('hex'); // ************* TASK 3: CALCULATE THE SIGNATURE ************* // Create the signing key using the function defined above. signingKey = getSignatureKey(secretKey, datestamp, region, serviceName); // Sign the string_to_sign using the signing_key signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest( 'hex'); // ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST ************* // The signing information can be either in a query string value or in // a header named Authorization. This code shows how to use a header. // Create authorization header and add to request headers authorizationHeader = algorithm + ' ' + 'Credential=' + accessKey + '/' + credentialScope + ', ' + 'SignedHeaders=' + signedHeaders + ', ' + 'Signature=' + signature; process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0 var options = { method: apiMethod, host: apiHost, path: apiEndpoint, headers: { 'X-Amz-Date': amzdate, 'Authorization': authorizationHeader } }; callback = function(response) { var str = ''; //another chunk of data has been recieved, so append it to `str` response.on('data', function(chunk) { str += chunk; }); console.log("CALLBACK",str); //the whole response has been recieved, so we just print it out here response.on('end', function() { console.log('Complete: ' + str); }); } console.log(options); https.request(options, callback).end();
错误信息:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Error> <Code>SignatureDoesNotMatch</Code> <Resource>archivestorage/objectNameNotDecodedYet</Resource> <Message>The request signature we calculated does not match the signature you provided. Check your secret access key and signing method.</Message> </Error>
排查关键点
- 签名头格式错误:
signedHeaders末尾多了分号,AWS要求签名头列表不能以分号结尾,应改为"host;x-amz-date"。 - 路径未编码:S3要求路径中的特殊字符必须做URI编码(比如空格、中文、特殊符号),Postman会自动处理,但代码中直接使用原始路径会导致签名不匹配,需对
apiEndpoint中的特殊字符进行编码。 - Secret Key处理:确保
secretKey原样使用,若包含斜杠等特殊字符,不要进行转义或修改。 - 时间同步问题:AWS签名对时间精度要求高,本地时间与UTC时间差不能超过5分钟,检查
amzdate和datestamp生成是否正确,建议使用UTC时间而非本地时间。 - 规范请求格式:确保
canonicalRequest的各部分之间严格用\n分隔,没有多余空格或换行;canonicalHeaders必须以\n结尾,且顺序要与signedHeaders一致。 - 服务与区域匹配:确认
serviceName(s3)和region(us-east-1)与目标S3桶的实际配置完全一致,需和Postman中的参数保持相同。
内容的提问来源于stack exchange,提问作者sourav_anand
相关产品推荐
相关产品推荐

