簡體   English   中英

Laravel 保護 Amazon s3 存儲桶文件

[英]Laravel secure Amazon s3 bucket files

我正在使用 Amazon s3,但在這里我面臨兩個問題

1.我在提交表單時無法直接將文件上傳到亞馬遜服務器。我的意思是我必須將圖像upload folder到我的 PHP 服務器上的upload folder ,然后我必須從那里檢索它們並將其上傳到s3 server 當我們點擊提交時,有沒有辦法將圖像直接上傳到s3

2.如果我在s3 put object傳遞'public' ,那么我可以訪問或查看文件,但如果我將其設為公開,則每個人都可以查看文件。 但是我需要保護所有文件並且只查看經過身份驗證的用戶。 任何人都可以建議我如何解決這個問題?

try {           
    $s3 = \Storage::disk('s3');
    $s3->put($strFileName, file_get_contents($img_path.$strFileName), 'public');
} catch (Aws\Exception\S3Exception $e) {
    echo "There was an error uploading the file.\n"+$e;
}

在提問之前,我已經閱讀了許多來自 stackoverflow 的答案,但它並沒有幫助我解決我的問題。 謝謝。

對於您的第一個問題,它可以直接將圖像上傳到 AWS S3。

$s3 = \Storage::disk('s3')->getDriver();
$s3->put($filePath, file_get_contents($file), array('ContentDisposition' => 'attachment; filename=' . $file_name . '', 'ACL' => 'public-read'));

您應該指定您的文件路徑和您從表單中獲得的文件。

1. 有沒有辦法在我們點擊提交時直接上傳圖片

是的

如何:

您需要分兩部分使用 JavaScript(使用 AJAX)來完成此操作;

a) 當用戶點擊“提交”時,您會捕獲此事件,首先上傳文件(參見http://docs.aws.amazon.com/AWSJavaScriptSDK/guide/browser-examples.html示例),然后 b) 然后提交通過 AJAX 處理表單並處理響應。

然而:

這允許用戶上傳任何內容並可能導致問題。 有一些提示(就在示例下方)可以創建 15 分鍾(可變)的經過身份驗證的 URL,但是如果用戶花費的時間超過 15 分鍾,或者嘗試在 15 分鍾內上傳 100 個文件,或者上傳圖像文件以外的內容,會發生什么情況,或格式錯誤的圖像文件等。

拉入您的服務器並驗證它們是圖像以及您需要的類型/大小,然后從服務器上傳會更安全。

當然,如果這是一個簡單的管理工具,並且您正在控制誰訪問代碼,那么就去做吧——希望您只上傳您期望的內容。

2. 我需要保護所有文件並且只查看經過身份驗證的用戶

通過“經過身份驗證的用戶”:如果您的意思是“上傳圖像的用戶”,那么 s3 本身不提供該功能,但 CloudFront 提供。 您可以發布預先授權的 URL 或簽名 cookie: http : //docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-choosing-signed-urls-cookies.html

如果“經過身份驗證的用戶”是指上傳文件的人,那么根據文檔,如果沒有訪問底層客戶端的權限,這在 Laravel 類中是不可能的。 默認情況下, publicprivate是您唯一的可見性選項,它們被轉換為public-read ,但您需要authenticated-readbucket-owner-read或其他預設授權之一(參考: http : //docs.aws.amazon .com/AmazonS3/latest/dev/acl-overview.html#canned-acl )如果經過authenticated-read或其他罐裝 ACL 授權沒有提供您需要的權限配置文件,您可以創建自己的(詳細信息)同一頁)。

解決方案是抓取底層客戶端,然后直接做put-object。 (然后如果你走那么遠,你也可以放棄 Laravel 庫並引入 s3 並自己做這一切 - 然后你就可以完全控制一切)。

$client = $disk->getDriver()->getAdapter()->getClient();

$client->putObject([
    'Bucket' => $bucket,
    'Key'    => $fileName,
    'Body'   => $fileBody,
    'ACL'    => 'authenticated-read'  /* Or which ACL suits */
]);

我最近解決了這個問題。 首先是的,您可以直接上傳到 s3,這是我用於獲取有關此信息的一些信息: http : //docs.aws.amazon.com/AmazonS3/latest/dev/HTTPPOSTExamples.html

首先,您需要創建一個策略和簽名服務器端以添加到您的 html 表單以上傳文件。

$policy = base64_encode(json_encode([
            "expiration" => "2100-01-01T00:00:00Z",
            "conditions" => [
                ["bucket"=> "bucketname"],
                ["starts-with", '$key', "foldername"],
                ["acl" => "public-read"],
                ["starts-with", '$Content-Type', "image/"],
                ["success_action_status" => '201'],
            ]
        ]));
$signature = base64_encode(hash_hmac('sha1',$policy,getenv('S3_SECRET_KEY'),true));

現在在我的表單前端,我不使用提交按鈕,您可以使用提交按鈕,但您需要捕獲提交並防止表單在上傳完成之前實際提交。

當我們點擊保存時,它會生成一個 md5(使用 npm 安裝)文件名,這樣文件名就不能真正被隨機猜測,然后它使用 ajax 將文件上傳到 S3。 完成后,它將文件數據和返回的 aws 數據放入隱藏輸入中並提交表單。 它應該是這樣的:

<form action="/post/url" method="POST" id="form">
    <input type="text" name="other_field" />
    <input type="file" class="form-control" id="image_uploader" name="file" accept="image/*" />
    <input type="hidden" id="hidden_medias" name="medias" value="[]" />
</form>
<input type="button" value="save" id="save" />
<script>
$(document).ready(function(){
    $('#save').click(function(){
            uploadImage(function () {
                $('#form').submit();
            });
    });
});
var uploadImage = function(callback) {
    var file = $('#image_uploader')[0].files[0];
    if(file !== undefined) {
        var data = new FormData();
        var filename = md5(file.name + Math.floor(Date.now() / 1000));
        var filenamePieces = file.name.split('.');
        var extension = filenamePieces[filenamePieces.length - 1];
        data.append('acl',"public-read");
        data.append('policy',"{!! $policy !!}");
        data.append('signature',"{!! $signature !!}");
        data.append('Content-type',"image/");
        data.append('success_action_status',"201");
        data.append('AWSAccessKeyId',"{!! getenv('S3_KEY_ID') !!}");
        data.append('key',filename + '.' + extension);
        data.append('file', file);

        var fileData = {
            type: file.type,
            name: file.name,
            size: file.size
        };

        $.ajax({
            url: 'https://{bucket_name}.s3.amazonaws.com/',
            type: 'POST',
            data: data,
            processData: false,
            contentType: false,

            success: function (awsData) {
                var xmlData = new XMLSerializer().serializeToString(awsData);
                var currentImages = JSON.parse($('#hidden_medias').val());
                currentImages.push({
                    awsData: xmlData,
                    fileData: fileData
                });
                $('#hidden_medias').val(JSON.stringify(currentImages));
                callback();
            },
            error: function (errorData) {
                console.log(errorData);
            }
        });
    }
};
</script>

監聽提交的控制器然后解析來自該輸入字段的 JSON 並創建一個 Media 實例(我創建的模型)並存儲每個圖像的awsDatafileData

然后,而不是像這樣將 html 圖像標簽指向 s3 文件:

<img src="https://{bucketname}.s3.amazonaws.com/filename.jpg" />

我做這樣的事情:

<img src="/medias/{id}" />

然后路由可以通過普通的auth中間件以及你在 Laravel 中需要做的所有事情。 最后,該路由指向執行此操作的控制器:

public function getResponse($id)
{
    $media = Media::find($id);
    return (new Response('',301,['Location' => $media->info['aws']['Location']]));
}

所以這只是簡單地使用 301 重定向並將標頭位置設置為實際的 aws 文件。 由於我們在將文件上傳到 aws 時會生成一個 md5 文件名,因此每個文件名都是一個 md5,因此人們無法在存儲桶中隨機搜索 aws 文件。

您的問題的解決方案,我也在使用,但沒有使用 laravel。

1. 要將任何文件直接上傳到特定文件夾中的 Amazon AWS S3 Bucket,您可以這樣做。

HTML

<form action="upload.php" enctype="multipart/form-data">
    <input type="file" name="file" id="file" />
    <button type="submit">Upload file</button>
</form>

PHP - 上傳.php

包括 aws php sdk

require "vendor/autoload.php";

初始化 S3 客戶端

$credentials = new Aws\Credentials\Credentials(
    '<AWS ACCESS KEY>', 
    '<AWS ACCESS SECRET>'
);

$s3Client = Aws\S3\S3Client::factory(
    [
        'credentials' => credentials
        'region' => 'us-east-1',
        'version' => 'latest'
    ]
);

創建文件上傳實體

$uploadEntity = array(
    'Bucket' => <S3 Bucket Name>,
    'Key'    => '<Upload_Folder_If_Any>/<FileName>',
    'Body'   => fopen($_FILES['file']['tmp_name'], 'r+'),
    //'ContentDisposition' => 'attachment; filename="<FileName>"' <-- If need to allow downloading
);

上傳到 s3 存儲桶

try {
    // $result will be Aws\Result object
    $result = $s3Client->putObject($uploadEntity);  
} catch (Aws\S3\Exception\S3Exception $exception) {
    // S3 Exception
}

2. 現在只將上傳的文件提供給經過身份驗證的用戶

首先,您需要為 s3 存儲桶創建私有存儲桶策略。

存儲桶策略- 要生成存儲桶策略,您可以使用Policy Generator 使用它,您可以生成這樣的策略。 復制自Improve.dk 網站

{
  "Id": "Policy1319566876317",
  "Statement": [
    {
      "Sid": "Stmt1319566860498",
      "Action": [
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::<BucketName>/*",
      "Principal": {
        "CanonicalUser": [
          "<CannoicalUserId_of_OAI>"
        ]
      }
    }
  ]
}

其次,您需要設置 cloudfront s3 Bucket 的私有網絡分發。 只有這樣做,您才能僅通過aws 簽名的 url 或簽名的 cookie將您的內容提供給經過身份驗證的用戶

第三,要生成簽名的 url,您將需要僅從 aws 控制台獲取的pem文件。

生成簽名網址

$cdnName = '<AWS CLOUDFRONT WEB DISTRIBUTION CDN>';
$assetName = '<UPLOAD_FOLDER_IF_ANY>/<FILENAME>';
$expiry = time() + 300;     // 5 mins expiry time, ie. the signed url will be valid only for 5 mins

$cloudfront = CloudFrontClient::factory(array(
    'credentials' => $credentials,
    'region' => 'us-east-1',
    'version' => 'latest'
));

// Use this for creating signed url
$signedUrl = $cloudFront->getSignedUrl([
    'url'         => $cdnName . '/' . $assetName,
    'expires'     => $expiry,
    'private_key' => '/path/to/your/cloudfront-private-key.pem',
    'key_pair_id' => '<cloudfront key pair id>'
]);

// Use this for signed cookie    
$signedCookie = $cloudFront->getSignedCookie([
    'url'         => $cdnName . '/' . $assetName,
    'expires'     => $expiry,
    'private_key' => '/path/to/your/cloudfront-private-key.pem',
    'key_pair_id' => '<cloudfront key pair id>'
]);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM