amazon-web-services - 访问 s3 资源的最安全方式是什么?
问题描述
问题标题很广泛,但我的问题不是。我只想澄清我的方法。我有一个阻止公共访问的 s3 存储桶。存储桶策略设置为 http-referer。这就是它的外观。
{
"Version": "2008-10-17",
"Id": "http referer policy example",
"Statement": [
{
"Sid": "Allow get requests referred by www.mysite.com and mysite.com",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::storage/*",
"Condition": {
"StringLike": {
"aws:Referer": [
"https://www.example.com/*",
"https://example.com/*",
]
}
}
}
]
}
如果我的前端(在我的 tld 上)尝试通过 URL 访问 s3 资源,我仍然会收到错误消息。(网址示例 - https://storage.s3.amazonaws.com/path/to/my/file.png
)。
我放弃了直接访问 s3 URL 的方法,并决定在我的 TLD 上构建一个后端实用程序,该实用程序将获取有问题的 s3 资源并将其发送回前端。所以 URL 看起来像这样,https://<tld>/fetch-s3-resource/path/to/file.png
.
我想知道这种方法是否正确,或者是否有更好的方法。在我看来,即使设置 http-referer 策略也没有任何意义,因为任何人都可以通过手动将 http-referer 设置为我的 TLD 来调用我的存储桶。
更新- 我发现了应该允许用户通过 URL 公开访问资源的签名 URL。这应该可以解决我的问题,但我仍然将公共访问设置为“关闭”,而且我真的不知道要切换哪个开关以允许具有签名 URL 的用户能够访问该资源。
这是 s3 签名 URL 的示例。这是文档的链接
import logging
import boto3
from botocore.exceptions import ClientError
def create_presigned_url(bucket_name, object_name, expiration=3600):
"""Generate a presigned URL to share an S3 object
:param bucket_name: string
:param object_name: string
:param expiration: Time in seconds for the presigned URL to remain valid
:return: Presigned URL as string. If error, returns None.
"""
# Generate a presigned URL for the S3 object
s3_client = boto3.client('s3')
try:
response = s3_client.generate_presigned_url('get_object',
Params={'Bucket': bucket_name,
'Key': object_name},
ExpiresIn=expiration)
except ClientError as e:
logging.error(e)
return None
# The response contains the presigned URL
return response
更新更新- 由于问题还不够清楚,而且我似乎对我的“松散”语言采取了一些自由,让我澄清一些事情。
1 - 我实际上想做什么?我想以这样一种方式保持我的 s3 存储桶的安全,只有具有“我”生成的预签名 URL 的用户才能访问那里的任何资源。2 - 当我问“我的方法”是否更好或者是否有任何其他方法时,我的意思是什么?我想知道是否有一种“本机”/aws 提供的方式来访问存储桶,而无需编写一个后端端点来获取资源并将其扔回前端。3 - 我如何衡量一种方法与另一种方法?我认为这一点很明显,如果您的框架提供了一个身份验证流程*,您就不要尝试从头开始编写身份验证流程*。这个逻辑在这里也适用,如果有办法访问 AWS 列出的对象,那么我可能不应该
解决方案
预签名的 URL 出现了。您可以阻止所有公共访问,但仍然能够生成签名 URL 并将其提供给前端。我已经在我的问题中链接了官方文档,这是我最终得到的最后一段代码。
def create_presigned_url(bucket_name, bucket_key, expiration=3600, signature_version='s3v4'):
"""Generate a presigned URL for the S3 object
:param bucket_name: string
:param bucket_key: string
:param expiration: Time in seconds for the presigned URL to remain valid
:param signature_version: string
:return: Presigned URL as string. If error, returns None.
"""
s3_client = boto3.client('s3',
aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
config=Config(signature_version=signature_version),
region_name='us-east-1'
)
try:
response = s3_client.generate_presigned_url('get_object',
Params={'Bucket': bucket_name,
'Key': bucket_key},
ExpiresIn=expiration)
except ClientError as e:
logging.error(e)
return None
# The response contains the pre-signed URL
return response
推荐阅读
- python - Python:ValueError 和 XLRDError 的异常处理
- python - 有条件地更改 Python Marshmallow 中的字段属性
- python - 根据列上的条件合并 2 个数据框
- php - 在 params 数组中回显文件内容
- javascript - 对具有对象数组的复杂对象动态执行 .join
- python - 如何对执行 SQL 的函数进行单元测试而不影响 Python 中的数据库?
- powershell - sudent,New-ADUser 多用户创建脚本的名称无效
- python - Python 3 帧中的奇怪行为
- r - 在R中按多列对数据框进行排序,不区分大小写
- python - 为什么`is`对于相同的实例方法和类方法返回False,但对于静态方法返回True