8 votes

Servez des fichiers en toute sécurité depuis Amazon S3

J'ai une application qui télécharge les fichiers des utilisateurs vers S3. Pour l'instant, la liste de contrôle d'accès des dossiers et des fichiers est définie comme privée.

J'ai créé une table de base de données (appelée docs) qui stocke les informations suivantes :

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

Ainsi, lorsqu'un utilisateur veut télécharger un fichier, je vérifie d'abord dans la table de la base de données qu'il a accès au fichier. Je préférerais que le fichier ne soit pas d'abord téléchargé sur mon serveur puis envoyé à l'utilisateur - je voudrais qu'il puisse récupérer le fichier directement sur Amazon.

Est-il possible de s'appuyer sur un hashname très très long (rendant pratiquement impossible à quiconque de deviner un nom de fichier au hasard) ? Dans ce cas, je peux définir l'ACL de chaque fichier sur public-read.

Ou bien, existe-t-il d'autres options que je peux utiliser pour servir les fichiers tout en les gardant privés ?

10voto

Eric J. Points 73338

N'oubliez pas qu'une fois que le lien existe, rien n'empêche un utilisateur de le partager avec d'autres. De même, rien n'empêche l'utilisateur d'enregistrer le fichier ailleurs et de partager un lien vers la copie du fichier.

La meilleure approche dépend de vos besoins spécifiques.

Option 1 - URL de téléchargement à durée limitée

Si cela s'applique à votre scénario, vous pouvez également créer des liens personnalisés expirant (limités dans le temps) vers le contenu S3. Cela permettrait à l'utilisateur de télécharger du contenu pendant une durée limitée, après quoi il devrait obtenir un nouveau lien.

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

Option 2 - URL obscurcie

Si vous préférez éviter de faire passer le fichier par votre serveur web plutôt que de risquer qu'une URL, même obscure, soit intentionnellement partagée, utilisez le nom de lien difficile à deviner. Cela permet à un lien de rester valide "pour toujours", ce qui signifie que le lien peut être partagé "pour toujours".

Option 3 - Télécharger via votre serveur

Si vous êtes préoccupé par le partage du lien et que vous souhaitez que les utilisateurs s'authentifient par l'intermédiaire de votre site Web, diffusez le contenu sur votre site Web après avoir vérifié les informations d'identification de l'utilisateur.

Cette option permet également au lien de rester valide "pour toujours", mais exige que l'utilisateur se connecte (ou peut-être simplement qu'un cookie d'authentification soit placé dans le navigateur) pour accéder au lien.

3voto

Josue Ibarra Points 854

Je veux juste poster la solution PHP avec le code, si quelqu'un a le même problème.

Voici le code que j'ai utilisé :

$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);
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X