为AWS请求逻辑生成签名 - 将SignatureDoesNotMatch返回

时间:2016-07-28 15:00:22

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

我正在尝试使用HTML POST表单和上传策略执行上传到S3,并且我正在努力创建签名以与其一起使用。

当我提交上传表单时,我一直收到403和SignatureDoesNotMatch回复。

以此为指导,http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-UsingHTTPPOST.html我想出了以下内容:

policy_hash = {
  'expiration' => (Time.now.utc + 3600 * 3).iso8601
}

@policy = Base64.encode64(JSON.dump(policy_hash)).gsub("\n","")

kDate    = OpenSSL::HMAC.digest('sha256', "AWS4" + @secret_access_key, Time.now.strftime("%Y%m%d"))
kRegion  = OpenSSL::HMAC.digest('sha256', kDate, AWS_REGION)
kService = OpenSSL::HMAC.digest('sha256', kRegion, "s3")
kSigning = OpenSSL::HMAC.digest('sha256', kService, "aws4_request")

@signature = Digest::SHA256.hexdigest(
  OpenSSL::HMAC.digest('sha256', kSigning, @policy)
)

我将政策和签名包括在内。我知道AWS_REGION@secret_access_key是正确的,因为我在其他地方使用它们。

任何人都可以看到上面的代码有什么问题吗?或有任何其他指导?

2 个答案:

答案 0 :(得分:0)

@signature = Digest::SHA256.hexdigest(
  OpenSSL::HMAC.digest('sha256', kSigning, @policy)
 )

你正在采取你的签名,而不是十六进制编码,你用SHA256和十六进制编码哈希对它进行哈希。

我不是一个红宝石的人,但这里有一个猜测你真正需要的东西:

@signature = OpenSSL::HMAC.hexdigest('sha256', kSigning, @policy)

答案 1 :(得分:0)

更新可以帮助将来的任何人,我最终使用aws-sdk gem为我处理所有的签名和表单构建。

@s3_base_path = "#{SecureRandom.uuid}/"
creds = Aws::Credentials.new(access_key_id, secret_access_key, session_token)
@post = Aws::S3::PresignedPost.new(creds.credentials, AWS_REGION, S3_BRANDING_FILES_BUCKET, {
  key_starts_with: @s3_base_path,
  acl: 'private',
  success_action_status: '201',
  server_side_encryption: 'AES256',
  signature_expiration: Time.now.utc + 3600 * 3
})

然后在视图中:

<!-- Direct Upload to S3 Form -->
<form action="<%= @post.url %>" method="POST" enctype="multipart/form-data">
  <% @post.fields.each do |name, value| %>
    <input type="hidden" name="<%= name %>" value="<%= value %>"/>
  <% end %>

  <!-- Key is the file's name on S3 and will be filled in with JS -->
  <input type="hidden" name="key" value="">
  <div class="hiddenfile" style="height:0; width:0; overflow:hidden;">
    <input type="file" accept="image/gif, image/jpeg" name="file" id="file-input">
  </div>
</form>