如何在 S3 中存储数据并允许用户使用 rails API / iOS 客户端以安全的方式访问?
Posted
技术标签:
【中文标题】如何在 S3 中存储数据并允许用户使用 rails API / iOS 客户端以安全的方式访问?【英文标题】:How to store data in S3 and allow user access in a secure way with rails API / iOS client? 【发布时间】:2012-06-04 09:03:15 【问题描述】:我是编写 Rails 和 API 的新手。我需要一些有关 S3 存储解决方案的帮助。这是我的问题。
我正在为 ios 应用程序编写一个 API,用户在 iOS 上使用 Facebook API 登录。服务器根据 Facebook 向 iOS 用户发出的令牌验证用户,并发出临时会话令牌。从这一点开始,用户需要下载存储在 S3 中的内容。此内容仅属于用户及其朋友的子集。该用户可以向 S3 添加更多内容,这些内容可以被同一群人访问。我想这类似于将文件附加到 Facebook 群组...
用户可以通过 2 种方式与 S3 交互...将其留给服务器或让服务器发出临时 S3 令牌(不确定此处的可能性),用户可以直接点击内容 URL到 S3。我发现这个问题是关于方法的,但是,它确实过时了(2 年前):Architectural and design question about uploading photos from iPhone app and S3
所以问题:
在颁发临时令牌时,是否有办法限制用户仅访问 S3 上的某些内容?我怎样才能做到这一点?假设有...比如说 100,000 或更多用户。 让 iOS 设备直接拉出这些内容是个好主意吗? 还是应该让服务器控制所有内容的传递(这当然解决了安全问题)?这是否意味着我必须先将所有内容下载到服务器,然后再将其传递给连接的用户? 如果您了解 rails...我可以使用回形针和 aws-sdk gem 来实现这种设置吗?对多个问题深表歉意,感谢您对问题的任何见解。谢谢:)
【问题讨论】:
找到了这个并认为我会为其他寻找docs.aws.amazon.com/AmazonS3/latest/dev/…的人发表评论 【参考方案1】:使用aws-sdk gem,您可以通过调用url_for
获取任何S3对象的临时签名url:
s3 = AWS::S3.new(
:access_key_id => 1234,
:secret_access_key => abcd
)
object = s3.buckets['bucket'].objects['path/to/object']
object.url_for(:get, :expires => 20.minutes.from_now, :secure => true ).to_s
这将为您提供一个仅用于 S3 中该对象的已签名临时使用 URL。它会在 20 分钟后过期(在本例中),它只对那个对象有效。
如果您有很多客户需要的对象,您将需要发布大量签名 URL。
或者应该让服务器控制所有内容传递(这当然解决了安全问题)?这是否意味着我必须先将所有内容下载到服务器,然后再将其传递给连接的用户?
请注意,这并不意味着服务器需要下载每个对象,它只需要验证并授权特定客户端访问 S3 中的特定对象。
来自亚马逊的 API 文档: https://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#RESTAuthenticationQueryStringAuth
【讨论】:
感谢@ejdyksen。我设计的解决方案正是使用的(我没有用我的答案更新问题)!所以我的解决方案是为 GET 请求做经过身份验证的 URL。但是,当用户贡献内容时,他会使用联合 IAM 令牌(过期的临时凭证)将资源创建到特定的 /bucket/user/objectname 位置,并附加策略以允许 /bucket/user/* 写入访问。因此系统中的任何用户都不能损害其他用户的内容。似乎工作正常。感谢您的回答。 如果您使用的是 v2 的 aws-sdk-ruby,请注意方法有些不同:docs.aws.amazon.com/sdkforruby/api/Aws/S3/… 用户可以看到我的访问密钥不是有风险吗?还有秘钥(转换后的) @Dennis 重点是文件不必访问您的服务器。该链接不包含您的 AWS 凭证。它可能包含ACCESS_KEY_ID
(我不记得我的头顶),但这不是秘密。
@ejdyksen 你是对的,我刚刚验证了 URL 只包含 AWS_ACCESS_KEY_ID
。我原本以为AWS_SECRET_ACCESS_KEY
也显示了,但事实并非如此。【参考方案2】:
以上答案使用旧的 aws-sdk-v1 gem 而不是新的 aws-sdk-resources 版本 2。
新方法是:
aws_resource = Aws::S3::Resource::new
aws_resource.bucket('your_bucket').object('your_object_key').presigned_url(:get, expires_in: 1*20.minutes)
your_object_key 是文件的路径。如果你需要查看它,你可以使用类似的东西:
s3 = Aws::S3::Client::new
keys = []
s3.list_objects(bucket: 'your_bucket', prefix: 'your_path').contents.each |e|
keys << e.key
这些信息非常难以挖掘,我几乎只是放弃并使用了较旧的宝石。
参考
http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#presigned_url-instance_method
【讨论】:
expires_in
需要以秒为单位的数据,请务必先转换。
"ArgumentError(预期 :expires_in 为秒数)"以上是关于如何在 S3 中存储数据并允许用户使用 rails API / iOS 客户端以安全的方式访问?的主要内容,如果未能解决你的问题,请参考以下文章
如何获取 Rails 应用程序的 CORS 标头以访问 aws s3 存储桶?
Rails ActiveStorage 附加到现有 S3 文件
如何允许 cognito 身份验证的用户获得对 s3 存储桶的公共访问权限