2012-08-14 39 views
8

我有一個將用戶文件上傳到S3的應用程序。目前,文件夾和文件的ACL被設置爲私有。從亞馬遜S3安全地提供文件

id 
user_id 
file_name (original file as specified by the user) 
hash_name (random hash used to save the file on amazon) 

因此,當用戶想要下載一個文件,我第一次在db表檢查,他們有機會獲得:存儲以下信息

我創建了一個數據庫表(稱爲文檔)文件。我寧願不先將文件下載到我的服務器,然後發送給用戶 - 我希望他們能夠直接從亞馬遜抓取文件。

可以依賴非常長的散列名(使任何人隨機猜測文件名基本上不可能)?在這種情況下,我可以將每個文件的ACL設置爲公開閱讀。

或者,還有其他的選擇,我可以用來提供文件,同時保持私人?

回答

9

請記住,一旦鏈接在那裏,沒有任何東西阻止用戶與他人共享該鏈接。然後再次,沒有什麼阻止用戶將文件保存在其他地方並共享到文件副本的鏈接。

最好的方法取決於您的具體需求。

選項1 - 有限時間的下載網址

如果適用於您的情況,您還可以創建到期的S3內容(有時間限制),自定義鏈接。這將允許用戶在有限的時間內下載內容,之後他們將不得不獲得新的鏈接。

http://docs.amazonwebservices.com/AmazonS3/latest/dev/S3_QSAuth.html

選擇2 - 混淆URL

如果你珍惜避免貫穿您的Web服務器上的文件上的風險,一個URL,但晦澀,可能會故意共享,然後用硬猜測鏈接名稱。這將允許鏈接保持「永久」有效,這意味着鏈接可以「永久」共享。

選項3 - 通過您的服務器

下載如果你擔心被共享的鏈接,當然希望用戶通過您的網站進行身份驗證,然後驗證用戶憑據後,服務通過您的網站內容。

該選項還允許鏈接保持「永久」有效,但要求用戶登錄(或者可能只是在瀏覽器中具有身份驗證Cookie)才能訪問該鏈接。

+0

所以,基本上,有沒有辦法讓ACL私人,仍然從亞馬遜服務呢?如何臨時將ACL更改爲公開讀取,然後從S3中提供,然後將ACL更改爲私有? – JonoB 2012-08-14 16:31:50

+0

查看我的更新回答。您可以生成時間受限的公開網址,但不會向世界開放ACL。 – 2012-08-14 16:36:19

+0

@EricJ。我可以知道如何使它認證的用戶查看images.if你知道然後你可以回答這個問題http://stackoverflow.com/questions/40168221/laravel-secure-amazon-s3-bucket-files.Thank you – iCoders 2016-10-21 04:30:18

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); 
} 
+0

很好的答案。完美工作。謝謝Josue! – 2014-09-09 05:32:40