403 S3 REST API HEAD请求上的禁止错误403

时间:2014-12-14 13:28:09

标签: rest amazon-s3 http-status-code-403

我正在尝试对S3 REST API执行HEAD对象请求但我仍然收到403 Forbidden错误,即使我在S3上具有必要权限的策略设置。响应主体是空的,所以我不认为它是一个签名问题。我已尝试对政策进行多项更改,但似乎没有任何改变。我能正常PUT对象和DELETE对象,只是HEAD无法正常工作。

这是我的保管政策:

{
"Statement": [
    {
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam:: 999999999999:user/User"
        },
        "Action": "s3:ListBucket",
        "Resource": "arn:aws:s3:::my-bucket"
    },
    {
        "Effect": "Allow",
        "Principal": {
            "AWS": "*"
        },
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::my-bucket/*"
    },
    {
        "Sid": "",
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam::999999999999:user/User"
        },
        "Action": [
            "s3:GetObject",
            "s3:GetObjectVersion",
            "s3:DeleteObject",
            "s3:PutObject"
        ],
        "Resource": "arn:aws:s3:::my-bucket/*"
    }
]
}

有什么想法吗?

更新

正如迈克尔指出的那样,我的签名似乎有问题,但我没有看到什么。

def generate_url options={}
options[:action] = options[:action].to_s.upcase
options[:expires] ||= Time.now.to_i + 100
file_path = "/" + @bucket_name + "/" + options[:file_name]

string_to_sign = ""
string_to_sign += options[:action]
string_to_sign += "\n\n#{options[:mime_type]}\n"
string_to_sign += options[:expires].to_s
string_to_sign += "\n"
string_to_sign += file_path

signature = CGI::escape(
  Base64.strict_encode64(
    OpenSSL::HMAC.digest('sha1', SECRET_KEY, string_to_sign)
  )
)

url = "https://s3.amazonaws.com"
url += file_path
url += "?AWSAccessKeyId=#{ACCESS_KEY}"
url += "&Expires=#{options[:expires]}"
url += "&Signature=#{signature}"
url
end

生成的要签名的字符串如下所示:

HEAD\n\n\n1418590715\n/video-thumbnails/1234.jpg"

解决方案:

在开发文件PUT部分的某个时刻,我实际上已经破坏了GET和HEAD。我传递一个空字符串作为请求的主体,而不是传递任何东西,使签名上需要mime类型并打破它,因为我没有提供mime类型。我只是删除了空的请求体,它工作得很好。感谢迈克尔指出我走错了方向(我浪费了很多时间来改变存储桶政策)。

5 个答案:

答案 0 :(得分:4)

它仍然可能是你的签名,我怀疑它是,原因如下:

您观察到信息正文是一个很好的观察;但是,它并不代表你所得出的结论意味着什么。

缺少响应主体并没有提供任何有关错误性质的信息,在这种情况下,因为Web服务器不应该返回一个正文以及HEAD响应,否则重要的是:

  

HEAD方法与GET相同,只是服务器MUST NOT在响应中返回消息正文

     

- http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html(RFC-2616)

对我进行测试,我确认S3对未签名的HEAD请求和错误签名的HEAD请求的回复没有区别:它&#39 ; s始终为HTTP/1.1 403 Forbidden,没有邮件正文。

另请注意,GET的签名网址对HEAD无效,反之亦然。

在S3 Signature Version 2和S3 Signature Version 4中,"要签名的字符串"包括" HTTP动词,"这将是GETHEAD,这意味着对GET有效的签名对HEAD无效,反之亦然......签名时必须知道方法,因为它是签名过程中使用的元素。

s3:GetObject权限是使用HEAD所需的唯一documented权限,如果GET正在运行,这似乎会消除权限问题,这表明签名是潜在的问题。

答案 1 :(得分:2)

确认HEAD预先签名的URL将获得403 Forbidden。 如果设置自定义标头,例如对象的内容类型。 403响应将不包含自定义标头,仍然可以获得application / xml。

答案 2 :(得分:0)

对@ Michael-sqlbot上面的答案的其他评论...

我面临相同的症状,但根本原因却不同。

如果您尝试对不存在的文件进行HEAD处理,那么这还将返回403禁止的错误, UNLESS 您具有s3:ListBucket权限。

就我而言,我拥有s3.GetObject,s3.PutObject和s3.HeadBucket权限,但是直到我添加s3.ListBucket才获得正确的404-找不到错误。

此处也对此进行了说明:https://aws.amazon.com/premiumsupport/knowledge-center/s3-rest-api-cloudfront-error-403/

答案 3 :(得分:0)

有相同的问题,但有不同的根本原因-试图创建一个存储桶,而不是获取404,而是得到403。由于S3是全局命名空间,所以其他人创建了存储桶,因此我拥有正确的存储桶权限和帐户设置,我仍然会从HEAD请求中获得403。解决方案是先检查存储桶是否全局存在,如果存在,请尝试使用其他存储桶名称。

答案 4 :(得分:0)

我也收到了这个错误提示;在 pytest 期间使用 freezegun。我已经冻结了过去的时间,并且收到了 403 错误。所以时钟偏差可能会导致这种情况。

我通过尝试另一个 API 调用发现了这个,我收到了:

E           botocore.exceptions.ClientError: An error occurred (RequestTimeTooSkewed) when calling the ListObjects operation: The difference between the request time and the current time is too large.