403 forbidden for amazon s3将api上传到Rails App中

时间:2017-09-22 19:40:48

标签: ruby-on-rails amazon-web-services amazon-s3

我从第三方应用程序

获得以下aws s3 api终点
https://xxx.s3.amazonaws.com/uploads/74d75512c28b49358846f959bd798536?Signature=lxBIZJD7DN4QK3LPmsHxR7D2eTA%3D&Expires=1506108780&AWSAccessKeyId=AKIAJG6Z6A5TUL7ULPXA

我正在尝试将PUT request这个网址设为upload an File,但始终获得以下error

#<Net::HTTPForbidden 403 Forbidden readbody=true>

更新以下是回复正文

<?xml version="1.0" encoding="UTF-8"?>
<Error>
   <Code>SignatureDoesNotMatch</Code>
   <Message>
      The request signature we calculated does not match the 
      signature you provided. Check your key and signing method.
  </Message>
  <AWSAccessKeyId>AKIAJG6Z6A5TUL7ULPXA</AWSAccessKeyId>
  <StringToSign>
    PUT

    application/xml
    1506144576
    /xxx/uploads/93a64f8081804604be917b4185c5ed58
  </StringToSign>
  <SignatureProvided>8pwtC2vtN4LuOwGc887AlT2ZnUc=</SignatureProvided>
  <StringToSignBytes>50 55 </StringToSignBytes>
  <RequestId>B2B18369BA23A92F</RequestId>
  <HostId>YCtjOJsfskITKxjW96ouZq1BV=</HostId>
</Error>

如果我inspect response它显示在data之后,但不明白这有什么问题?没有其他线索,任何人都可以提供帮助将不胜感激。

{
 "x-amz-request-id" => [
    [0] "385D5CADFE6175FC"
],
       "x-amz-id-2" => [
    [0] "4uD51Gb/rJy0QooQVmF25Qbp0E568bB9v1P4Grg9CTM2dJ/Iiccad/IyuuEnWDphlGZrr8ZUnQw="
],
     "content-type" => [
    [0] "application/xml"
],
"transfer-encoding" => [
    [0] "chunked"
],
             "date" => [
    [0] "Fri, 22 Sep 2017 19:28:01 GMT"
],
           "server" => [
    [0] "AmazonS3"
]
}

我正在运行以下代码段

uri = URI.parse(aws_api_end_point)
request = Net::HTTP::Put.new(uri)

request.body = File.read(file_path)
request.content_type = 'application/xml'

http = Net::HTTP.start(uri.host, uri.port, :use_ssl => true)
response = http.request(request)

注意::我没有使用任何aws SDK。

1 个答案:

答案 0 :(得分:1)

请求签名是确定性的 - 对于给定时刻的给定请求,只有一个有效签名。出于所有实际目的,反之亦然 - 对于任何签名,您只能做出一个有效请求。其他任何东西,签名都不匹配。

该算法的设计不是逆向工程,因此我们无法说出他们在给您签名时要求您做出的请求。

但是,我们确实有这个。我相信有些空白丢失了,所以我把它添加回来了:

<StringToSign>
  PUT

  application/x-www-form-urlencoded
  1506144576

  /xxx/uploads/93a64f8081804604be917b4185c5ed58
</StringToSign>

这是您提出的请求(不是您应该提出的请求),使用此伪代码转换为canonical form

StringToSign = 
  HTTP-VERB + "\n" +
  Content-MD5 + "\n" +
  Content-Type + "\n" +
  Expires + "\n" +
  CanonicalizedAmzHeaders + 
  CanonicalizedResource;   

问题最明显的候选人是Content-Type。几乎可以肯定,他们不希望您使用application/x-www-form-urlencoded因为S3 PUT对象操作不使用HTML表单上传。 S3 PUT期望请求正文中对象的原始八位字节,以及Content-Type标头匹配。 S3本身实际上并不验证它们是否匹配(标题与正文),但至少没有预期的 Content-Type标题,上传将被阻止。

如果您向第三方API提供Content-Type,那么您的上传需要在S3上传时使用相同的类型,因为签名需要它。

不幸的是,出于故障排除的目的,无法使用预先签名的URL使请求无效的事情无数。来自第三方的文档应阐明他们希望您做出的后续请求的结构。