我目前正在使用
Ruby aws-sdk,版本2 gem和服务器端客户提供的加密密钥(SSE-C).我可以将对象从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
但是我在检索对象和生成签名的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
该链接已生成,但当我点击它时,它会指示我进入亚马逊页面说.
<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>
错误消息没有帮助,因为我不确定我需要添加哪些参数.我想我可能会遗漏一些权限参数.
获取方法
http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#get-instance_method
Presigned_Url方法
http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#presigned_url-instance_method
最佳答案 生成预先签名的GET对象URL时,需要提供所有传递给Aws :: S3 :: Object#get的相同参数.
s3.get(sse_customer_algorithm: 'AES256', sse_customer_key: customer_key).body.read
这意味着您需要将相同的sse_customer_ *选项传递给#presigned_url:
url = obj.presigned_url(:get,
sse_customer_algorithm: 'AES256',
sse_customer_key: customer_key)
这将确保SDK在您发出最终GET请求时正确签署Amazon S3期望的标头.下一个问题是您现在负责将这些值与GET请求一起作为标头发送. 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))
})
请注意 – 在测试时,我在aws-sdk gem的当前v2.0.33版本的预签名URL实现中发现了一个错误. This has been fixed now并且一旦发布就应该成为v2.0.34的一部分.
请参阅以下gitst以获取修补该bug并演示的完整示例:
>使用cpk上传对象
>使用SDK获取对象
>生成预先签名的GET URL
>仅使用Net :: HTTP和预签名URL下载对象
您可以在此处查看示例脚本:
https://gist.github.com/trevorrowe/49bfb9d59f83ad450a9e
只需替换脚本顶部的bucket_name和object_key变量即可.