Amazon S3 - 如何修复“我们计算的请求签名与签名不匹配”错误?

Posted

技术标签:

【中文标题】Amazon S3 - 如何修复“我们计算的请求签名与签名不匹配”错误?【英文标题】:Amazon S3 - How to fix 'The request signature we calculated does not match the signature' error? 【发布时间】:2015-08-11 16:33:13 【问题描述】:

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

我在 AWS SDK 上运行在 php 5.3 上的 PHP V2.8.7。

我正在尝试使用以下代码连接到我的 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'
                ]
            ]
        ]
    ]
];

它正在产生以下错误:

我们计算的请求签名与您提供的签名不匹配。检查您的密钥和签名方法。

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

【问题讨论】:

所以,AWS SDK 只是实现了一堆直接的 API 调用。使用 AWS,您进行的每一次调用都会使用您的私钥(或上面的 secret),并使用它来根据您的访问密钥、当前时间戳以及许多其他因素来计算签名。见docs.aws.amazon.com/general/latest/gr/…。这是一个远景,但考虑到它们包括时间戳,也许您本地环境的时间已经关闭? 当我们在对象元数据中传递了不正确的大小 (Content-Length) 时发生。 (长版:我们直接将输入流从 Java HttpServletRequest 传递到 S3 客户端,并通过元数据将 request.getContentLength() 作为 Content-Length 传递;当 servlet(随机)接收分块请求时(Transfer-Encoding: chunked) , getContentLength() 正在返回 -1 - 这导致 putObject 失败(随机)。晦涩难懂;但显然是我们的错,因为我们传递了不正确的对象大小。) 乔什我的笔记本电脑时间是一个小时(出于某种原因,它被设置为莫斯科而不是伦敦时间)。感谢您的帮助! 第一次访问,请浏览很多答案,在很多情况下您会收到此错误以及此页面中给出的各种解决方案 就我而言,对于 opensearch,我在路径和 URL 中给出了不同的信息... 【参考方案1】:

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

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

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

【讨论】:

前导斜线也对我造成了这个问题。你只需要路径/到/文件,而不是/路径/到/文件 对我来说,问题是键内的空格 补充一点,当我的密钥中有一个加号 + 时,我收到了这个错误消息。 在我的情况下,这是由于 bucket 参数中有路径引起的。而不是bucket = "bucketname",我有bucket = "bucketname/something"。这也给出了签名不匹配错误。 当我没有在上传文件请求中提供 Content-Type 标头时,我得到了这个【参考方案2】:

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

【讨论】:

我只是双击key_hash_lala/key_hash_continues,它只选择了一个部分。唉,告诉用户“密码错误,伙计!”有多难? 第一次从可下载的 csv 复制密钥时遇到问题。对于我创建的第二个密钥,我只是从浏览器中复制了它,没有任何问题 +1 到 @nthaxis - 从 .csv 复制导致失败 - 直接从浏览器复制,效果很好 对我来说,这也是凭据错误的结果。我在凭据中遗漏了一个字符。【参考方案3】:

我在尝试复制带有一些 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进行编码来解决

【讨论】:

谢谢,和我一起工作!我还尝试对“密钥”进行编码,因为该密钥还包含 UTF8 字符,并且它最终位于错误的目录中。只有对 CopySource 进行编码才能正常工作。【参考方案4】:

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

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

【讨论】:

在我偶然发现这个之前尝试了很多东西!这就是我的答案。 为我工作,文件路径正常,其他一切正常,目前其他应用程序正在使用相同的功能,并且永远不会在该应用程序中出现此错误。谢谢,奥列格【参考方案5】:

此错误似乎主要发生在您的密钥前后有空格时

【讨论】:

有同样的问题。 Skype 有时会复制带有空行的值。只需将其粘贴到记事本中,然后复制不带空格即可。 是的!还要检查您在任何其他标题中是否有空格。【参考方案6】:

实际上在 Java 中我遇到了同样的错误。花了 4 个小时调试它后,我发现问题出在 S3 对象中的元数据中,因为在 s3 文件中放置缓存控件时有空间。这个空间是允许的1.6.* 版本,但在 1.11.* 中是不允许的,因此会引发签名不匹配错误

【讨论】:

如果您在元数据中传递了不正确的Content-Length,也会发生这种情况【参考方案7】:

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

【讨论】:

长时间后救了我。谢谢!!【参考方案8】:

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

我在复制/粘贴键时没有检查特殊字符。让我绊倒了几分钟。

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

secretAccessKey: 'Gk/JCK77STMU6VWGrVYa1rmZiq+Mn98OdpJRNV614tM'

变成

secretAccessKey: 'Gk\/JCK77STMU6VWGrVYa1rmZiq\+Mn98OdpJRNV614tM'

【讨论】:

【参考方案9】:

对我来说,我使用 axios 并且默认发送标题

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)

【讨论】:

同样,更改 content-type 成功了。【参考方案10】:

在 aws-php-sdk 的早期版本中,在弃用 S3Client::factory() 方法之前,您可以放置​​文件路径的一部分,或 Key,因为它在 S3Client->putObject() parameters 中被调用, 在桶参数上。我在生产中使用了一个文件管理器,使用 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'
]);

我必须将存储桶/密钥路径的 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。错误消息确实指出了问题:

我们计算的请求签名与您的签名不匹配 假如。 检查您的密钥和签名方法。

所以,我的Key 错了,因为我的Bucket 错了。

【讨论】:

感谢您发布此信息,当我看到“检查您的密钥”时,我认为访问密钥或密钥有误。在我的情况下,它是对象键(和存储桶)。因此,按照您的描述移动存储桶和对象键值是可行的。亚马逊需要澄清他们抱怨 IMO 的关键。再次感谢【参考方案11】:

对于 Python 集 - signature_version s3v4

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

【讨论】:

确实如此。更多信息在这里:aws.amazon.com/premiumsupport/knowledge-center/…【参考方案12】:

我遇到了同样的问题,我遇到的问题是我导入了错误的环境变量,这意味着我的 AWS 密钥错误。根据阅读所有答案,我将验证您的所有访问 ID 和密钥是否正确,并且没有其他字符或任何其他内容。

【讨论】:

【参考方案13】:

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

aws configure

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

希望这会有所帮助!

【讨论】:

【参考方案14】:

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

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

【讨论】:

我遇到了这个问题,您的建议已解决!谢谢@Sebastian【参考方案15】:

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

例如:

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

被解析成:

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

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

【讨论】:

【参考方案16】:

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

【讨论】:

【参考方案17】:

我刚刚体验了使用带有 React Native 的 AWS 开发工具包将图像上传到 S3 的过程。原来是ContentEncoding参数引起的。

删除该参数“修复”了问题。

【讨论】:

【参考方案18】:

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

【讨论】:

这对我有用。用于生成签名 URL 的 HTTP 动词(PUT、POST)必须与使用该 URL 执行上传时使用的动词相同。【参考方案19】:

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

【讨论】:

新访问密钥也对我有用 - 谢天谢地,我从阅读 github.com/aws/aws-sdk-js/issues/86#issuecomment-153433220 中得到了提示,就我而言,是 SQS 在标题中引发了异常。我之前使用的密钥(出现异常时)是 97 天前,IAM 仪表板中有感叹号【参考方案20】:

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

【讨论】:

【参考方案21】:

像其他人一样,我也有类似的问题,但在 java sdk v1.1 中。对我来说,以下 2 个修复对我有帮助。

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

应用这两个修复程序后,它起作用了。所以我的建议不是坚持下去。如果没有其他工作,请尝试升级库。

【讨论】:

【参考方案22】:

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

【讨论】:

【参考方案23】:

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

使用Pretty 标签复制并粘贴网址,看看它是否真的有效。

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

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

【讨论】:

你能告诉我你是如何解决这个问题的吗?它在邮递员中工作正常,但在 nodejs 中却不行【参考方案24】:

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

【讨论】:

您能否添加更多详细信息在哪里投放 AWS Sign ?【参考方案25】:

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

【讨论】:

当我阅读上面的答案时,我仔细检查了我的密钥并意识到我在末尾添加了 /。【参考方案26】:

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

只是为那些可能会错过他们信用末尾令人沮丧的无形空间的人添加这个。

【讨论】:

【参考方案27】:

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

【讨论】:

【参考方案28】:

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

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

【讨论】:

【参考方案29】:

我在使用 Debian 延伸可用的最新 awscli 版本(即版本 1.11.13)时,在具有非 AWS S3 端点的 Docker 映像中遇到此问题。

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

使用基于 Debian 拉伸映像的 Dockerfile 安装最新版本的 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

【讨论】:

【参考方案30】:

我必须设置

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

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

【讨论】:

以上是关于Amazon S3 - 如何修复“我们计算的请求签名与签名不匹配”错误?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 amazon sdk 为虚域生成预签名的 Amazon S3 url?

如何授予 Amazon SES 写入您的 Amazon S3 存储桶的权限

如何通过http访问amazon s3

如何将 Apache Kafka 与 Amazon S3 连接?

如何检测 Amazon S3 中的变化? [复制]

如何使用 getSignedUrl 操作从 Amazon s3 访问对象