PHP。亚马逊S3签名V4。简单的例子

时间:2016-01-19 08:34:35

标签: php amazon-s3

我的PHP应用程序我使用简单的函数集上传到amazon 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

我似乎创建了工作示例。签名似乎通过了。我收到了“Signature不匹配”等错误。然后我纠正了这个错误。 但现在我还有其他错误:

亚马逊的回应是:

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?

1 个答案:

答案 0 :(得分:2)

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

Sqlbot的AWS最佳实践,这是一本我还没写过的书(还有?),它会告诉你跟踪每个存储桶位置的理想解决方案是规范化您使用适当的区域主机名存储的每个S3 URI。对于example中名为us-west-2的广告资源,有效网址包含以下内容:

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

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

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

如果不维护存储区到区域映射的配置表,以这种形式存储S3对象引用可能是处理签名版本4所需的区域特定验证的最佳方法。

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

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

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

乍一看,V4有点令人生畏,有可能让人联想到#34;它没有被打破,所以为什么要修复它?&#34;但V4引入了安全增强功能,使其成为一种更安全的机制,而且 - 我在此推测 - 为AWS基础架构中的凭据提供增强的安全性。 AWS如何在内部实施它不是公共信息,但V4的逻辑结构表明它可以防止各个AWS区域和服务需要拥有您的密钥。在AWS中,给定服务仅需要访问给定日期,区域和服务的签名密钥,以便对您的请求进行身份验证,这意味着AWS似乎已至少部分实现了V4,并着眼于内部 Principle of Least Privilege在他们自己的基础设施中的应用......这是值得称赞的。