web-dev-qa-db-ja.com

PHPを使用して保護されたAmazonS3イメージを安全なサイトに表示するにはどうすればよいですか?

サイトの画像をホストからAmazonS3クラウドホスティングに移動しようとしています。これらの画像はクライアントの作業現場のものであり、一般に公開することはできません。できればAmazonから入手できるPHP SDKを使用して、自分のサイトに表示してほしい。

これまでのところ、変換のスクリプトを作成して、データベース内のレコードを検索し、ファイルパスを取得して適切な名前を付け、Amazonに送信することができました。

    //upload to s3
$s3->create_object($bucket, $folder.$file_name_new, array(
    'fileUpload' => $file_temp,
    'acl' => AmazonS3::ACL_PRIVATE, //access denied, grantee only own
    //'acl' => AmazonS3::ACL_PUBLIC, //image displayed
    //'acl' => AmazonS3::ACL_OPEN, //image displayed, grantee everyone has open permission
    //'acl' => AmazonS3::ACL_AUTH_READ, //image not displayed, grantee auth users has open permissions
    //'acl' => AmazonS3::ACL_OWNER_READ, //image not displayed, grantee only ryan
    //'acl' => AmazonS3::ACL_OWNER_FULL_CONTROL, //image not displayed, grantee only ryan
    'storage' => AmazonS3::STORAGE_REDUCED
    )
    );

すべてをコピーする前に、画像のアップロードと表示をテストするための簡単なフォームを作成しました。 ACL_PRIVATEを使用して画像をアップロードすると、公開URLを取得してアクセスできなくなるか、一時キーを使用して公開URLを取得して画像を表示できます。

<?php
//display the image link
$temp_link = $s3->get_object_url($bucket, $folder.$file_name_new, '1 minute');
?>
<a href='<?php echo $temp_link; ?>'><?php echo $temp_link; ?></a><br />
<img src='<?php echo $temp_link; ?>' alt='finding image' /><br />

この方法を使用すると、キャッシュはどのように機能しますか?ページを更新したり、レコードの1つを変更したりするたびに、その画像を再度プルして、getリクエストを増やすと思います。

また、バケットポリシーを使用して、特定のリファラーからの画像検索のみを許可することも検討しました。 Amazonは指定したページまたはドメインからのリクエストのみをフェッチすることになっていることを正しく理解していますか?

参照しました: https://forums.aws.Amazon.com/thread.jspa?messageID=188183&#18818 設定しましたが、オブジェクトに必要なセキュリティについて混乱しています。前述のように一時リンクを使用しない限り、プライベートにした場合でも表示されないように見えました。それらを公開すれば、リファラーに関係なく、直接ナビゲートできます。

私はここでやろうとしていることから離れていますか?これは実際にはS3でサポートされていませんか、それとも単純なものが不足していますか? SDKのドキュメントと多くの検索を確認しましたが、これはもう少し明確にドキュメント化されているはずなので、ここでの入力がこの状況で他の人に役立つことを願っています。一意のIDでファイルに名前を付け、隠すことでセキュリティを作成する他の人を読んだことがありますが、それでは私の状況ではうまくいかず、セキュリティを確保しようとする人にとってはおそらくベストプラクティスではありません。

27
Bob

画像を提供する最良の方法は、PHP SDKを使用してURLを生成することです。これにより、ダウンロードはS3からユーザーに直接送信されます。

@mfondaが提案したように、サーバー経由でダウンロードする必要はありません。S3オブジェクトに任意のキャッシュヘッダーを設定できます。ダウンロードすると、S3を使用することによる大きなメリットが失われます。

ただし、質問で指摘したように、URLは常に変更されるため(実際にはクエリ文字列)、ブラウザはファイルをキャッシュしません。簡単な回避策は、常に同じ有効期限を使用して、同じクエリ文字列が常に生成されるようにすることです。または、URLを自分で(データベースなどに)「キャッシュ」して、毎回再利用することをお勧めします。

明らかに、有効期限をはるか先のどこかに設定する必要がありますが、必要に応じて、これらのURLを頻繁に再生成できます。たとえば、データベースには、生成されたURLと有効期限を保存します(URLからも解析できます)。次に、既存のURLを使用するか、有効期限が過ぎている場合は新しいURLを生成します。等...

24
Geoff Appleford

Amazonバケットでバケットポリシーを使用して、アプリケーションのドメインがファイルにアクセスできるようにすることができます。実際、ローカル開発ドメイン(例:mylocaldomain.local)をアクセスリストに追加することもでき、画像を取得できるようになります。 Amazonはここでサンプルバケットポリシーを提供します: http://docs.aws.Amazon.com/AmazonS3/latest/dev/AccessPolicyLanguage_UseCases_s3_a.html 。これは、画像を提供するのに非常に役立ちました。

以下のポリシーは、私をこのSOトピックに導いた問題を解決しました:

    {
       "Version":"2008-10-17",
       "Id":"http referer policy example",
       "Statement":[
    {
      "Sid":"Allow get requests originated from www.example.com and example.com",
      "Effect":"Allow",
      "Principal":"*",
      "Action":"s3:GetObject",
      "Resource":"arn:aws:s3:::examplebucket/*",
      "Condition":{
        "StringLike":{
          "aws:Referer":[
            "http://www.example.com/*",
            "http://example.com/*"
          ]
        }
      }
    }
  ]
}
9
Wes

セキュリティと許可されていないユーザーからのデータの保護について話すとき、何かが明らかです。資格のあるリソースにアクセスするたびに確認する必要があります。

つまり、誰でもアクセスできるURLを生成することを意味します(取得するのは難しいかもしれませんが、それでも...)。唯一の解決策はイメージプロキシです。あなたはphpスクリプトでそれを行うことができます。

読み取りファイルを使用して推測するAmazonのブログからのすばらしい記事があります http://blogs.aws.Amazon.com/php/post/Tx2C4WJBMSMW68A/Streaming-Amazon-S3-Objects-From-a-Web-Server

readfile('s3://my-bucket/my-images/php.gif');
2
catalinux

S3からコンテンツをダウンロードして(PHPスクリプトで)、正しいヘッダーを使用して提供できます。

大まかな例として、image.phpに次のものがあるとします。

$s3 = new AmazonS3();
$response = $s3->get_object($bucket, $image_name);
if (!$response->isOK()) {
    throw new Exception('Error downloading file from S3');
}
header("Content-Type: image/jpeg");
header("Content-Length: " . strlen($response->body));
die($response->body);

次に、HTMLコードで次のことができます。

<img src="image.php">
0
mfonda