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

Mar*_*llo 7 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/*"
    }
]
}
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

更新:

正如迈克尔指出的那样,我的签名似乎是一个问题,尽管我没有看到什么.

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
Run Code Online (Sandbox Code Playgroud)

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

HEAD\n\n\n1418590715\n/video-thumbnails/1234.jpg"
Run Code Online (Sandbox Code Playgroud)

解:

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

Mic*_*bot 6

仍然可能是您的签名,出于以下原因,我怀疑是这样的:

您对消息正文的观察是很好的观察;但是,这并不意味着您已得出结论。

在这种情况下,缺少响应正文根本不会给您任何有关错误性质的信息,因为无论如何,Web服务器都不应随HEAD响应一起返回正文:

HEAD方法与GET其他方法相同,除了服务器MUST NOT在响应中返回消息正文

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

在我这方面进行测试,我确认S3对未签名HEAD请求和对错误签名HEAD请求的响应没有什么不同:它始终HTTP/1.1 403 Forbidden没有消息正文。

另请注意,的签名URL GET不适用于HEAD,反之亦然。

在S3 签名版本2和S3 签名版本4中,“要签名的字符串”包括“ HTTP动词” ,即为GETHEAD,表示对其有效的签名GET无效HEAD,反之亦然...签名时必须知道request方法,因为它是签名过程中使用的元素。

s3:GetObject权限是使用所需的唯一记录的权限HEAD,这似乎可以消除权限(如果有的话GET)的问题(如果正在运行),它可以将签名作为潜在问题。


小智 6

确认 HEAD 预签名 URL 将收到 403 Forbidden。如果设置自定义标头,例如对象的内容类型。403 响应将不包含自定义标头,但仍会获取 application/xml。


ptj*_*tty 5

对上面@Michael-sqlbot 的回答的附加评论......

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

如果您尝试 HEAD 一个不存在的文件,那么这也会返回 403 禁止错误,除非您拥有 s3:ListBucket 权限。

就我而言,我拥有 s3.GetObject、s3.PutObject 和 s3.HeadBucket 权限,但直到添加 s3.ListBucket 后,我​​才收到正确的 404 - 未找到错误。

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