尝试生成预签名 url link 以便用户可以下载 Amazon S3 对象,但请求无效
Trying to generate a presigned url link so an user can download an Amazon S3 object, but getting invalid request
我目前正在使用 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 link 供用户下载时遇到了一些问题。
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
link 已生成,但当我单击它时,它会将我定向到一个亚马逊页面,上面写着。
<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
当您生成 pre-signed GET object URL 时,您需要提供将传递给 Aws::S3::Object#get
.[=20= 的所有相同参数]
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 正确签署 Amazon S3 在您发出最终 GET 请求时期望的 headers。下一个问题是您现在负责将这些值与 GET 请求一起作为 headers 发送。 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
当前 v2.0.33 版本的预签名 URL 实现中存在一个错误 gem。 This has been fixed now 一旦发布,应该成为 v2.0.34 的一部分。
请参阅以下 gitst 以获取修补错误和演示的完整示例:
- 使用 cpk
上传 object
- 使用 SDK
获取 object
- 生成预签名 GET url
- 仅使用 Net::HTTP 和预先签名的 URL
下载 object
您可以在此处查看示例脚本:
https://gist.github.com/trevorrowe/49bfb9d59f83ad450a9e
只需替换脚本顶部的 bucket_name
和 object_key
变量。
我目前正在使用 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 link 供用户下载时遇到了一些问题。
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
link 已生成,但当我单击它时,它会将我定向到一个亚马逊页面,上面写着。
<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
当您生成 pre-signed GET object URL 时,您需要提供将传递给 Aws::S3::Object#get
.[=20= 的所有相同参数]
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 正确签署 Amazon S3 在您发出最终 GET 请求时期望的 headers。下一个问题是您现在负责将这些值与 GET 请求一起作为 headers 发送。 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
当前 v2.0.33 版本的预签名 URL 实现中存在一个错误 gem。 This has been fixed now 一旦发布,应该成为 v2.0.34 的一部分。
请参阅以下 gitst 以获取修补错误和演示的完整示例:
- 使用 cpk 上传 object
- 使用 SDK 获取 object
- 生成预签名 GET url
- 仅使用 Net::HTTP 和预先签名的 URL 下载 object
您可以在此处查看示例脚本:
https://gist.github.com/trevorrowe/49bfb9d59f83ad450a9e
只需替换脚本顶部的 bucket_name
和 object_key
变量。