【问题标题】:PHP. Amazon S3 Signature V4. Simple examplephp。亚马逊 S3 签名 V4。简单的例子
【发布时间】:2019-05-08 18:09:47
【问题描述】:

我的 PHP 应用程序使用了一组简单的函数上传到亚马逊 S3。 我的代码使用签名版本 2。一切正常。但它不适用于不支持签名 V2 的新区域。

我尝试实现签名 V4,但它看起来太复杂了。我只是无法为签名 V4 制作工作示例。

AWS SDK for PHP 支持 V4 登录。但这对我来说太复杂了。我不能使用那个 SDK(因为 PHP 5.2 我不能升级它)

在我当前的代码中,我有 V2 的简单代码

$stringToSign="PUT\n\n$contentType\n$httpDate\nx-amz-acl:$acl\n";
$stringToSign.="/$resource";
$signature = $this->constructSig($stringToSign);
$req->addHeader("Authorization", "AWS " . $this->accessKeyId . ":" . $signature);

function constructSig($str) {
    $hasher = new Crypt_HMAC($this->secretKey, "sha1");
    $signature = $this->hex2b64($hasher->hash($str));
    return($signature);
}

有没有可能有这么简单的constructSigV4函数来创建新的签名类型?

另外,我明白了,新类型签名需要有桶区域。如果我不知道存储桶区域,那该怎么办?每次请求之前都请求存储桶区域?我在不同地区都有存储桶。

更新。

有简单的例子https://github.com/chrismeller/awstools/blob/master/aws/signature/v4.php

我似乎创建了工作示例。签名似乎通过了。我收到诸如“签名不匹配”之类的错误。然后我纠正直到这个错误消失。 但现在我有其他错误:

亚马逊的回应是:

HTTP/1.1 411 Length Required

<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>MissingContentLength</Code><Message>You must provide the Content-Length HTTP header.</Message>

但是 Content-Length 包含在我的请求中

PUT /259001/checkmark-circle.png HTTP/1.1
Host: ******.s3.amazonaws.com
Content-Type: image/png
Content-Length: 2338
x-amz-acl: private
x-amz-content-sha256: STREAMING-AWS4-HMAC-SHA256-PAYLOAD
X-AMZ-Date: Tue, 19 Jan 2016 07:33:01 -0500
Date: Tue, 19 Jan 2016 07:33:01 -0500
Authorization: AWS4-HMAC-SHA256 Credential=************/20160119/us-east-1/s3/aws4_request,SignedHeaders=host;x-amz-acl;x-amz-content-sha256;x-amz-date,Signature=c2bb290f2d54d31bc95785705530e10e0a8bde4c7b7dd1ef3b11a8fa7d96a57c

有什么问题吗?为什么它说 Content-Length is missing if it is present?

【问题讨论】:

    标签: php amazon-s3


    【解决方案1】:

    请参阅Retrieve bucket's objects without knowing bucket's region with AWS S3 REST API 了解如何学习任何存储桶的区域。 tl;dr:您可以要求 S3 的任何区域为您提供存储桶的位置,或者您可以使用嵌入在该区域错误时发生的错误中的信息。

    Sqlbot's Best Practices for AWS,这是一本我还没有真正写过(还没有?)的书,它会告诉您跟踪每个存储桶位置的理想解决方案是将您存储的每个 S3 URI 规范化为适当的区域主机名。对于 us-west-2 中名为 example 的存储桶,有效 URL 包括:

    https://example.s3.amazonaws.com/
    https://example.s3-us-west-2.amazonaws.com/
    

    这两种方式都会将请求发送到正确的区域,因为第一种形式 *.s3.amazonaws.com 使用 S3 自身管理的 DNS 自动将请求发送到正确的区域端点,而第二种形式在主机名中明确包含区域端点。由于跨区域存在一致的模式,因此如果您以这种方式在内部存储 URL,则可以相对轻松地从主机名中提取正确的区域。

    注意上述情况的例外是 us-east-1 区域,由于遗留原因,该区域在主机名中需要 s3.amazonaws.coms3-external-1.amazonaws.com。您的代码将需要处理这种情况。

    不维护存储桶到区域映射的配置表,以这种形式存储 S3 对象引用可能是处理 Signature Version 4 所需的特定于区域的身份验证的最佳方式。

    乍一看,Signature V4 确实比 V2 复杂得多,实际上,签名代码并不像您为 V2 展示的那样紧凑,但如果您设法让 V2 工作,我有信心你可以让V4工作。

    有一个官方的 Signature Version 4 测试套件,您应该会发现它非常有用 - 它为您提供了几组输入(请求)参数、正确的最终结果,也许最重要的是,它为您提供了结果的中间签名步骤,以便您可以隔离实现的哪个部分没有生成正确的值以供后续步骤使用。几乎按照定义,签名算法实现中的任何轻微错误都会产生非常不正确的结果,这使得很难查明你可能做错了什么。测试套件绝对可以帮助您让代码走上正轨。

    V2 和 V4 之间的显着区别在于 V4 涉及创建一个签名密钥,它使用您的密钥、服务、区域和日期,并且使用此签名密钥而不是使用最终签署请求时直接使用密钥。

    乍一看,V4 有点吓人,可能会让人联想到“它没有坏,所以他们为什么要修复它?”这样的回答。但是 V4 引入了安全增强功能,使其成为一种更安全的机制,而且——我在这里推测——为您在 AWS 基础设施中的凭证提供了增强的安全性。 AWS 如何在内部实施它不是公开信息,但 V4 的逻辑结构表明它可以防止各个 AWS 区域和服务需要拥有您的密钥。在 AWS 中,给定的服务只需要访问给定日期、区域和服务的签名密钥,即可对您的请求进行身份验证,这意味着 AWS 似乎至少部分实施了 V4,着眼于内部 Principle of Least Privilege 在他们自己的基础设施中的应用......这是值得称赞的。

    【讨论】:

    • 我的签名工作正常。但我现在有其他问题。你有什么想法? (请看我的更新)
    • 这是一个不同的问题,但我怀疑这里的错误消息有点不精确。使用x-amz-content-sha256: STREAMING-AWS4-HMAC-SHA256-PAYLOAD 会使签名和上传过程更加复杂——而不是更少——并且需要您使用修改后的分块传输编码形式、计算字节数和生成中间签名。见docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html。您最好使用正确的x-amz-content-sha256 为您上传的对象计算正确的签名。
    • 感谢您的回复。我将尝试学习分块传输并使用它。我无法计算文件的哈希值,因为上传开始时我不知道文件正文。我从流中读取了一个文件,但我无法读取它 2 次。
    猜你喜欢
    • 1970-01-01
    • 2012-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-12
    相关资源
    最近更新 更多