简体   繁体   English

尝试生成预先指定的URL链接,以便用户可以下载Amazon S3对象,但获取无效请求

[英]Trying to generate a presigned url link so an user can download an Amazon S3 object, but getting invalid request

I am currently using the Ruby aws-sdk, version 2 gem with server-side customer-provided encryption key(SSE-C). 我目前正在使用Ruby aws-sdk,版本2 gem和服务器端客户提供的加密密钥(SSE-C)。 I am able to upload the object from a rails form to Amazon S3 with no issues. 我可以将对象从rails表单上传到Amazon S3,没有任何问题。

def s3
  Aws::S3::Object.new(
    bucket_name: ENV['S3_BUCKET'],
    key: 'hello',
  )
end

def upload_object
  customer_key = OpenSSL::Cipher::AES.new(256, :CBC).random_key
  customer_key_md5 = Digest::MD5.new.digest(customer_key)
  object_key = 'hello'
  options = {}
  options[:key] = object_key
  options[:sse_customer_algorithm] = 'AES256'
  options[:sse_customer_key] = customer_key
  options[:sse_customer_key_md5] = customer_key_md5
  options[:body] = 'hello world'
  options[:bucket] = ENV['S3_BUCKET']
  s3.put(options)
  test_params = {
    object_key: object_key,
    customer_key: Base64.encode64(customer_key),
    md5_key: Base64.encode64(customer_key_md5),
  }
  Test.create(test_params)
end

But I'm having some issues with retrieving the object and generating a signed url link for the user to download it. 但是我在检索对象和生成签名的URL链接以供用户下载时遇到了一些问题。

def retrieve_object(customer_key, md5)
  options = {}
  options[:key] = 'hello
  options[:sse_customer_algorithm] = 'AES256'
  options[:sse_customer_key] = Base64.decode64(customer_key)
  options[:sse_customer_key_md5] = Base64.decode64(md5)
  options[:bucket] = ENV['S3_BUCKET']
  s3.get(options)
  url = s3.presigned_url(:get)
end

The link is generated, but when I clicked on it, it directs me to an amazon page saying. 该链接已生成,但当我点击它时,它会指示我进入亚马逊页面说。

<Error>
<Code>InvalidRequest</Code>
<Message>
The object was stored using a form of Server Side Encryption. The correct   parameters must be provided to retrieve the object.
</Message>
<RequestId>93684EEBA062B1C2</RequestId>
<HostId>
OCnn5EG7ydfoKzsmEDMbqK5kOhLFpNXxVRdekfhOfnBc6s+jtPYFsKi8IZsEPcd9ConbYUHgwC8=
</HostId>
</Error>

The error message is not helping as I'm unsure what parameters I need to add. 错误消息没有帮助,因为我不确定我需要添加哪些参数。 I think I might be missing some permissions parameters. 我想我可能会遗漏一些权限参数。

Get Method http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#get-instance_method 获取方法http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#get-instance_method

Presigned_Url Method http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#presigned_url-instance_method Presigned_Url方法http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#presigned_url-instance_method

When you generate a pre-signed GET object URL, you need to provide all of the same params that you would pass to Aws::S3::Object#get . 生成预先签名的GET对象URL时,需要提供所有传递给Aws::S3::Object#get的相同参数。

s3.get(sse_customer_algorithm: 'AES256', sse_customer_key: customer_key).body.read

This means you need to pass the same sse_customer_* options to #presigned_url : 这意味着您需要将相同的sse_customer_ *选项传递给#presigned_url

url = obj.presigned_url(:get,
  sse_customer_algorithm: 'AES256',
  sse_customer_key: customer_key)

This will ensure that the SDK correctly signs the headers that Amazon S3 expects when you make the final GET request. 这将确保SDK在您发出最终GET请求时正确签署Amazon S3期望的标头。 The next problem is that you are now responsible for sending those values along with the GET request as headers. 下一个问题是您现在负责将这些值与GET请求一起作为标头发送。 Amazon S3 will not accept the algorithm and key in the query string. Amazon S3将不接受查询字符串中的算法和键。

uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.request_uri, {
  "x-amz-server-side-encryption-customer-algorithm" => 'AES256',
  "x-amz-server-side-encryption-customer-key" => Base64.encode64(cpk),
  "x-amz-server-side-encryption-customer-key-MD5" => Base64.encode64(OpenSSL::Digest::MD5.digest(cpk))
})

Please note - while testing this, I found a bug in the presigned URL implementation of the current v2.0.33 version of the aws-sdk gem. 请注意 - 在测试时,我在aws-sdk gem的当前v2.0.33版本的预签名URL实现中发现了一个错误。 This has been fixed now and should be part of v2.0.34 once it releases. 现在已经修复了这个问题 ,一旦它发布就应该成为v2.0.34的一部分。

See the following gitst for a full example that patches the bug and demonstrates: 请参阅以下gitst以获取修补该bug并演示的完整示例:

  • Uploads an object using a cpk 使用cpk上传对象
  • Gets the object using the SDK 使用SDK获取对象
  • Generates a presigned GET url 生成预先签名的GET URL
  • Downloads the object using just Net::HTTP and the presigned URL 仅使用Net :: HTTP和预签名URL下载对象

You can view the sample script here: 您可以在此处查看示例脚本:

https://gist.github.com/trevorrowe/49bfb9d59f83ad450a9e https://gist.github.com/trevorrowe/49bfb9d59f83ad450a9e

Just replace the bucket_name and object_key variables at the top of the script. 只需替换脚本顶部的bucket_nameobject_key变量即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM