我有一个将用户文件上传到S3的应用。目前,文件夹和文件的ACL设置为私有。
我创建了一个存储以下信息的db表(称为docs):
id
user_id
file_name (original file as specified by the user)
hash_name (random hash used to save the file on amazon)
因此,当用户想要下载文件时,我首先在db表中检查他们是否有权访问文件。我不希望首先将文件下载到我的服务器然后发送给用户 - 我希望他们能够直接从亚马逊获取文件。
依靠非常长的hashname是否可以(任何人都无法随机猜出文件名)?在这种情况下,我可以将每个文件的ACL设置为public-read。
或者,我可以使用其他选项来提供文件,同时保密吗?
答案 0 :(得分:9)
请记住,一旦链接在那里,没有什么可以阻止用户与他人共享该链接。然后,没有什么能阻止用户将文件保存到别处并共享指向文件副本的链接。
最佳方法取决于您的具体需求。
选项1 - 限时下载网址
如果适用于您的方案,您还可以创建到S3内容的过期(有时间限制)自定义链接。这将允许用户在有限的时间内下载内容,之后他们将不得不获得新的链接。
http://docs.amazonwebservices.com/AmazonS3/latest/dev/S3_QSAuth.html
选项2 - 模糊的网址
如果您重视通过Web服务器运行文件的价值超过了可能会故意共享URL(无论多么模糊)的风险,那么请使用难以猜测的链接名称。这将允许链接“永远”保持有效,这意味着链接可以“永久”共享。
选项3 - 通过您的服务器下载
如果您担心要共享的链接,并且当然希望用户通过您的网站进行身份验证,请在验证用户凭据后通过您的网站提供内容。
此选项还允许链接“永久”保持有效,但要求用户登录(或者只是在浏览器中有一个身份验证cookie)才能访问该链接。
答案 1 :(得分:2)
我只想发布带有代码的PHP解决方案,如果有人遇到同样的问题。
这是我使用的代码:
$aws_access_key_id = 'AKIAIOSFODNN7EXAMPLE';
$aws_secret_key = 'YourSecretKey12345';
$aws_bucket = 'bucket';
$file_path = 'directory/image.jpg';
$timeout = '+10 minutes';
// get the URL!
$url = get_public_url($aws_access_key_id,$aws_secret_key,$aws_bucket,$file_path,$timeout);
// print the URL!
echo($url);
function get_public_url($keyID, $s3Key, $bucket, $filepath, $timeout)
{
$expires = strtotime($timeout);
$stringToSign = "GET\n\n\n{$expires}\n/{$aws_bucket}/{$file_path}";
$signature = urlencode(hex2b64(hmacsha1($s3Key, utf8_encode($stringToSign))));
$url = "https://{$bucket}.s3.amazonaws.com/{$file_path}?AWSAccessKeyId={$keyID}&Signature={$signature}&Expires={$expires}";
return $url;
}
function hmacsha1($key,$data)
{
$blocksize=64;
$hashfunc='sha1';
if (strlen($key)>$blocksize)
$key=pack('H*', $hashfunc($key));
$key=str_pad($key,$blocksize,chr(0x00));
$ipad=str_repeat(chr(0x36),$blocksize);
$opad=str_repeat(chr(0x5c),$blocksize);
$hmac = pack(
'H*',$hashfunc(
($key^$opad).pack(
'H*',$hashfunc(
($key^$ipad).$data
)
)
)
);
return bin2hex($hmac);
}
function hex2b64($str)
{
$raw = '';
for ($i=0; $i < strlen($str); $i+=2)
{
$raw .= chr(hexdec(substr($str, $i, 2)));
}
return base64_encode($raw);
}