Amazon S3 - 如何修复 'The request signature we calculated does not match the signature' 错误?

Amazon S3 - How to fix 'The request signature we calculated does not match the signature' error?

我已经在网上搜索了两天多,可能已经浏览了大部分在线记录的场景和解决方法,但到目前为止对我没有任何帮助。

我在 AWS SDK PHP V2.8.7 运行 PHP 5.3.

我正在尝试使用以下代码连接到我的 Amazon S3 存储桶:

// Create a `Aws` object using a configuration file
$aws = Aws::factory('config.php');

// Get the client from the service locator by namespace
$s3Client = $aws->get('s3');

$bucket = "xxx";
$keyname = "xxx";

try {
    $result = $s3Client->putObject(array(
        'Bucket' => $bucket,
        'Key' => $keyname,
        'Body' => 'Hello World!'
    ));

    $file_error = false;
} catch (Exception $e) {
    $file_error = true;

    echo $e->getMessage();

    die();
}

我的config.php文件如下:

return [
    // Bootstrap the configuration file with AWS specific features
    'includes' => ['_aws'],
    'services' => [
        // All AWS clients extend from 'default_settings'. Here we are
        // overriding 'default_settings' with our default credentials and
        // providing a default region setting.
        'default_settings' => [
            'params' => [
                'credentials' => [
                    'key'    => 'key',
                    'secret' => 'secret'
                ]
            ]
        ]
    ]
];

它产生了以下错误:

The request signature we calculated does not match the signature you provided. Check your key and signing method.

我已经检查了我的访问密钥和秘密至少 20 次,生成了新的,使用了不同的方法来传递信息(即配置文件并在代码中包含凭据),但目前没有任何效果。

调试了两天,终于发现问题了...

我分配给对象的键以句点开头,即 ..\images\ABC.jpg,这导致了错误的发生。

我希望 API 提供更有意义和相关的错误消息,唉,我希望这会帮助其他人!

我使用错误的凭据收到此错误。原来贴的时候好像有不可见字符

我在尝试复制带有一些 UTF8 字符的对象时遇到了同样的问题。下面是一个 JS 例子:

var s3 = new AWS.S3();

s3.copyObject({
    Bucket: 'somebucket',
    CopySource: 'path/to/Weird_file_name_ðÓpíu.jpg',
    Key: 'destination/key.jpg',
    ACL: 'authenticated-read'
}, cb);

通过使用 encodeURIComponent()

编码 CopySource 解决

实际上,在 Java 中,我同样 error.After 花了 4 个小时来调试它,我发现问题出在 S3 对象的元数据中,因为有 space 而s3 files.This space 中的缓存控件在 1.6.* 版本中是允许的,但在 1.11.* 中是不允许的,因此会抛出签名不匹配错误

我遇到了类似的错误,但对我来说,这似乎是由于在两个不同的 Elastic Beanstalk 环境中重复使用 IAM 用户来使用 S3 造成的。我通过 为每个环境创建一个具有相同权限的 IAM 用户 来处理这个症状,这使错误消失了。

如果上述其他解决方案的 none 适合您,请尝试使用

aws configure

this command 将打开一组选项,询问密钥、区域和输出格式。

希望对您有所帮助!

我刚刚体验过使用带有 React Native 的 AWS SDK 将图像上传到 S3。原来是ContentEncoding参数引起的

删除该参数"fixed" 问题。

在我的例子中,bucketname 是错误的,它包含密钥的第一部分 (bucketxxx/keyxxx) - 签名没有任何问题。

在我的例子中,我将 S3 url 解析为其组件。

例如:

Url:    s3://bucket-name/path/to/file

被解析为:

Bucket: bucket-name
Path:   /path/to/file

路径部分包含前导“/”导致请求失败。

在我的例子中 (python) 它失败了,因为我在文件中有这两行代码,继承自旧代码

http.client.HTTPConnection._http_vsn = 10 http.client.HTTPConnection._http_vsn_str = 'HTTP/1.0'

我可以通过设置环境变量来解决这个问题。

export AWS_ACCESS_KEY=
export AWS_SECRET_ACCESS_KEY=

在 IntelliJ + py.test 中,我使用 [Run] > [Edit Configurations] > [Configuration] > [Environment] > [Environment variables]

设置环境变量

另一个可能的问题是元值包含非 US-ASCII 字符。对我来说,它有助于在将值添加到 putRequest 时对值进行 UrlEncode:

request.Metadata.Add(AmzMetaPrefix + "artist", HttpUtility.UrlEncode(song.Artist));
request.Metadata.Add(AmzMetaPrefix + "title", HttpUtility.UrlEncode(song.Title));

我在使用 Debian stretch 可用的最新 awscli 版本(即版本 1.11.13)时使用非 AWS S3 端点的 Docker 图像中遇到此问题。

升级到 CLI 版本 1.16.84 解决了这个问题。

使用基于 Debian 拉伸图像的 Docker 文件安装最新版本的 CLI,而不是:

RUN apt-get update
RUN apt-get install -y awscli
RUN aws --version

使用:

RUN apt-get update
RUN apt-get install -y python-pip
RUN pip install awscli
RUN aws --version

我必须设置

Aws.config.update({
  credentials: Aws::Credentials.new(access_key_id, secret_access_key)
})

在 ruby aws sdk v2 之前(其他语言中可能也有类似的东西)

对我来说,我使用了 axios,默认情况下它发送 header

content-type: application/x-www-form-urlencoded

所以我改为发送:

content-type: application/octet-stream

并且还必须将此 Content-Type 添加到 AWS 签名

const params = {
    Bucket: bucket,
    Key: key,
    Expires: expires,
    ContentType: 'application/octet-stream'
}

const s3 = new AWS.S3()
s3.getSignedUrl('putObject', params)

在以前版本的 aws-php-sdk 中,在弃用 S3Client::factory() 方法之前,您可以放置​​部分文件路径,或者 Key 因为它在 S3Client->putObject() parameters 中被调用,在 bucket 参数上。我有一个生产使用的文件管理器,使用 v2 SDK。由于工厂方法仍然有效,所以更新到 ~3.70.0 后我没有重新访问这个模块。今天我花了两个小时的大部分时间来调试为什么我开始收到这个错误,结果是由于我传递的参数(曾经有效):

$s3Client = new S3Client([
    'profile' => 'default',
    'region' => 'us-east-1',
    'version' => '2006-03-01'
]);
$result = $s3Client->putObject([
    'Bucket' => 'awesomecatpictures/catsinhats',
    'Key' => 'whitecats/white_cat_in_hat1.png',
    'SourceFile' => '/tmp/asdf1234'
]);

我必须将 bucket/key 路径的 catsinhats 部分移动到 Key 参数,如下所示:

$s3Client = new S3Client([
    'profile' => 'default',
    'region' => 'us-east-1',
    'version' => '2006-03-01'
]);
$result = $s3Client->putObject([
    'Bucket' => 'awesomecatpictures',
    'Key' => 'catsinhats/whitecats/white_cat_in_hat1.png',
    'SourceFile' => '/tmp/asdf1234'
]);

我认为正在发生的事情是 Bucket 名称现在正在 URL 编码。在进一步检查我从 SDK 收到的确切消息后,我发现:

https://s3.amazonaws.com/awesomecatpictures%2Fcatsinhats/whitecats/white_cat_in_hat1.png

上执行 PutObject 时出错

AWS HTTP 错误:客户端错误: PUT https://s3.amazonaws.com/awesomecatpictures%2Fcatsinhats/whitecats/white_cat_in_hat1.png 结果是 403 Forbidden

这说明我提供给我的Bucket参数的/已经过urlencode(),现在是%2F.

签名的工作方式相当复杂,但问题归结为存储桶和密钥用于生成加密签名。如果它们在调用客户端和 AWS 中不完全匹配,则请求将被拒绝并显示 403。错误消息实际上指出了问题:

The request signature we calculated does not match the signature you provided. Check your key and signing method.

所以,我的 Key 是错误的,因为我的 Bucket 是错误的。

我不知道是否有人在尝试在浏览器中测试输出的 URL 时遇到过这个问题,但是如果您使用的是 Postman 并尝试复制生成的 url AWS 从 RAW 选项卡,因为转义反斜杠,你会得到上面的错误。

使用 Pretty 选项卡复制并粘贴 url 以查看它是否真的有效。

我最近 运行 遇到了这个问题,这个解决方案解决了我的问题。这是为了测试目的,看看你是否真的通过 url.

检索数据

此答案是对那些尝试从 AWS 生成下载、临时 link 或通常从 AWS 生成 URL 以供使用的人的参考。

我的问题是用于配置 Amplify 的 API 网关 URL 末尾有一个额外的斜线...

查询的 url 看起来像 https://....amazonaws.com/myapi//myendpoint。我删除了 conf 中的额外斜杠并且它起作用了。

这不是我一生中最明确的错误信息。

在我的例子中,我调用了 s3request.promise().then() 错误,这导致在只完成一次调用时发生了两次请求执行。

我的意思是我在遍历6个对象,但是发出了12个请求(你可以通过登录控制台或在浏览器中调试网络来检查)

由于第二个不需要的请求的时间戳与第一个请求的签名不匹配,因此产生了这个问题。

我遇到了同样的问题。我有默认方法,PUT 设置为定义 pre-signed URL 但试图执行 GET。错误是由于方法不匹配。

我在nodejs中有同样的错误。但是在 s3 构造函数中添加 signatureVersion 帮助了我:

const s3 = new AWS.S3({
  apiVersion: '2006-03-01',
  signatureVersion: 'v4',
});

通过 Java SDK 将文档上传到 CloudSearch 时出现此错误。问题是因为要上传的文档中的特殊字符。错误 "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method." 非常具有误导性。

生成新的访问密钥对我有用。

正如其他人所说,我遇到了完全相同的问题,结果证明它与密码/访问机密有关。我为我的 s3 用户生成了一个无效的密码,并且它没有通知我。尝试与用户连接时,出现此错误。它似乎不喜欢密码中的某些或所有符号(至少对于 Minio)

由于以下原因,我遇到了同样的错误。

我输入了正确的凭据,但使用的是复制粘贴。所以这可能是复制粘贴时插入垃圾字符的问题。 我已经手动输入 运行 代码,现在可以正常工作了

谢谢

大多数情况下是因为密钥错误 (AWS_SECRET_ACCESS_KEY)。请交叉验证您的 AWS_SECRET_ACCESS_KEY。希望它能奏效...

我通过在 AWS.S3() 中添加 apiVersion 解决了这个问题,然后它完美适用于 S3 签名 url.

变化自

var s3 = new AWS.S3();

var s3 = new AWS.S3({apiVersion: '2006-03-01'});

更详细的示例,可以参考这个AWS Doc SDK示例: https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/javascript/example_code/s3/s3_getsignedurl.js

只是为了增加这可以显示的许多不同方式。

如果您在 iOS 上使用 Safari 并且您已连接到 Safari Technology Preview 控制台 - 您将看到同样的问题。如果您与控制台断开连接 - 问题就会消失。

当然,这会使解决其他问题变得困难,但它是 100% 重现的。

我想弄清楚我可以在 STP 中更改什么以阻止它这样做,但还没有找到它。

在我的例子中,当我需要使用 s3.getSignedUrl('putObject') 时我使用了 s3.getSignedUrl('getObject')(因为我正在使用 PUT 上传我的文件),这就是签名不匹配的原因.

当我在 ~/.aws/credentials.

中的键周围加上引号时,我得到了这个

aws_secret_access_key = "KEY"

我在尝试复制对象时遇到此错误。我通过对 copySource 进行编码来修复它。这个其实在方法文档中是有描述的:

Params: copySource – The name of the source bucket and key name of the source object, separated by a slash (/). Must be URL-encoded.

CopyObjectRequest objectRequest = CopyObjectRequest.builder()
                .copySource(URLEncoder.encode(bucket + "/" + oldFileKey, "UTF-8"))
                .destinationBucket(bucket)
                .destinationKey(newFileKey)
                .build();

就我而言,在将文件上传到存储桶和为它们生成预签名 URL 之间我不得不等待几个小时。

这主要发生在您使用 SECRET 密钥并将其传递给弹性客户端时。

例如: 密钥:ABCW1233**+OxMMMMMMM8x**

在客户端配置时,只需要传入:ABCW1233**(+号前的部分)。

就我而言,在 AWS 签名授权方法中使用邮递员发出请求时,我使用 S3(大写)作为服务名称

如果您的密钥

之前或之后有一个space,这个错误似乎主要发生

调试并花费大量时间后,就我而言,问题出在 access_key_id 和 secret_access_key,只需仔细检查您的凭据或生成新凭据(如果可能)并确保您正在传递参数中的凭据。

奇怪的是我之前有一个错误The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256。 Whosebug 上有一个答案需要添加 AWS_S3_REGION_NAME = 'eu-west-2' (your region)AWS_S3_SIGNATURE_VERSION = "s3v4.

这样做之后,之前的错误就清除了,但我又遇到了这个签名错误。搜索答案,直到我最终删除 AWS_S3_SIGNATURE_VERSION = "s3v4 然后它起作用了。把它放在这里也许对某人有帮助。顺便说一句,我正在使用Django。

对于Python集-signature_versions3v4

s3 = boto3.client(
   's3',
   aws_access_key_id='AKIAIO5FODNN7EXAMPLE',
   aws_secret_access_key='ABCDEF+c2L7yXeGvUyrPgYsDnWRRC1AYEXAMPLE',
   config=Config(signature_version='s3v4')
)

我的 AccessKey 中有一些特殊字符没有正确转义。

我在执行 copy/paste 键时没有检查特殊字符。把我绊倒了几分钟。

一个简单的反斜杠修复了它。示例(显然不是我的真实访问密钥):

secretAccessKey: 'Gk/JCK77STMU6VWGrVYa1rmZiq+Mn98OdpJRNV614tM'

变成

secretAccessKey: 'Gk\/JCK77STMU6VWGrVYa1rmZiq\+Mn98OdpJRNV614tM'

我遇到了同样的问题,我遇到的问题是我导入了错误的环境变量,这意味着我的 AWS 密钥是错误的。在阅读所有答案的基础上,我将验证您所有的访问 ID 和密钥都是正确的,并且没有任何额外的字符或任何东西。

当我故意给出错误的秘密密钥时,它给出了这个错误。我期待一些有效的错误消息详细信息,例如“身份验证失败”或其他内容

没有什么我能看到的充分理由,删除存储桶并重新创建它对我有用。

和其他人一样,我也遇到了类似的问题,但在 java sdk v1 中。对我来说,以下 2 个修复帮助了我。

  1. 我的对象键看起来像这样 /path/to/obj/。在此,我首先删除了开头的/
  2. 另外,仅第1点并没有解决问题。我将我的 sdk 版本从 1.9.x 升级到 1.11.x

应用这两个修复程序后,它起作用了。所以我的建议是不要把它弄出来。如果没有别的工作,请尝试升级库。

我遇到了同样的问题。导致问题的代码片段:

<iframe title="PDF Viewer" src={`${docPdfLink}&embed=true`} />

对我来说,有两个问题

  1. 在 link 末尾使用 embed 导致签名不匹配,因此,出现了问题。
  2. S3 中的文件具有 application/pdf 以外的内容类型,因此即使在修复第一个点后我也无法呈现 pdf。

所以,这是我在代码中所做的:

<iframe title="PDF Viewer" src={docPdfLink} />

在 s3 存储桶中:s3 file content type 此外,我们还需要确保每当我们向 s3 添加或创建 pdf 时,它应该具有应用程序内容 application/pdf

在我的例子中,api 调用参数的顺序不正确导致了这种情况。

例如,当我打电话给 /api/call1?parameter1=x&parameter2=y 时,我收到了以下消息:

"The signature of the request did not match calculated signature."

交换参数后:/api/call1?parameter2=y&parameter1=x,api 调用按预期工作。

非常令人沮丧,因为 api 文档本身的参数顺序不同。这也不是发生这种情况的唯一电话。

这个问题发生在我身上是因为我不小心将 ACCESS_KEY_ID 的值赋给了 SECRET_ACCESS_KEY_ID。修复后一切正常。

这些更改对我有用。 修改代码

发件人: const s3 = new AWS.S3();

收件人: const s3 = new AWS.S3({ api版本:'2006-03-01', 签名版本:'v4', });

将方法调用从 POST 更改为 PUT。

我在 C# 中遇到了同样的问题。事实证明,当您尝试直接访问主体时,问题出在 restsharp return 主体的方式上。在我们的例子中,它与带有此正文的 /feeds/2021-06-30/documents 端点一起使用:

{
    "contentType":"text/xml; charset=UTF-8"
}

问题是当尝试在 HashRequestBody 方法上对 AWSSignerHelper class 上的请求签名时,您有以下代码:

 public virtual string HashRequestBody(IRestRequest request)
    {
        Parameter body = request.Parameters.FirstOrDefault(parameter => ParameterType.RequestBody.Equals(parameter.Type));
        string value = body != null ? body.Value.ToString() : string.Empty;
        return Utils.ToHex(Utils.Hash(value));
    }

此时body.Value.ToString()的值将是:

{contentType:text/xml; charset=UTF-8}

它缺少 restsharp 在 post 请求时添加的双引号,但是当您访问这样的值时,它不会给出无效的散列,因为该值与已发送一个。

我暂时用它替换了代码并且它有效:

public virtual string HashRequestBody(IRestRequest request)
    {
        Parameter body = request.Parameters.FirstOrDefault(parameter => ParameterType.RequestBody.Equals(parameter.Type));
        string value = body != null ? body.Value.ToString() : string.Empty;
        if (body?.ContentType == "application/json")
        {
            value = Newtonsoft.Json.JsonConvert.SerializeObject(body.Value);
        }
        return Utils.ToHex(Utils.Hash(value));
    }

如果您是 Android 开发人员并且正在使用问题 AWS sample code, you are most likely wondering why the ListS3Object works but not the GetS3Object. This is because when you set the setDoOutput(true) and using GET HTTP method, Android's HttpURLConnection switches the request to a POST. Thus, invalidating your signature. Check my 中的签名功能。

根据java docs of files uploading to S3 bucketIf you are uploading Amazon Web Services KMS-encrypted objects, you need to specify the correct region of the bucket on your client and configure Amazon Web Services Signature Version 4 for added security. For more information on how to do this, see http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingAWSSDK.html# specify-signature-version

所以您可能需要配置签名版本4。

我刚遇到这个,我有点不好意思说,这是因为我使用的是 HTTP POST 请求而不是 PUT。

尽管我很尴尬,但我还是想分享一下,以免有人挠头一个小时。

我在使用 SDK 的共享环境中遇到此错误,但使用相同的 key/secret 和 aws cli,它工作正常。构建系统脚本在密钥、秘密和会话密钥之后有一个 space,代码也读入了这些密钥。所以我的解决方法是调整构建脚本以在使用变量后删除 spaces。

只是为可能会错过学分末尾令人沮丧的隐形 space 的任何人添加此内容。