Evitar links externos con Amazon S3

Si hemos elegido Amazon S3 como sistema de almacenamiento virtual , quizás nos interese tener almacenados archivos que se puedan descargar libremente por cualquier usuario, y que además puedan ser linkados desde cualquier sitio. Pero en la mayoría de los casos tendremos almacenados nuestros archivos y no nos gustará que nadie nos enlace directamente y tener que soportar los gastos de transferencia y almacenamiento por él.

Voy a explicar cómo, con un sencillo script en php conseguiremos que nuestros archivos de S3 estén totalmente protegidos y que sólo puedan ser accesibles desde nuestro dominio.

Lo primero de todo, es conocer dos características que Amazon nos prové con sus APIs:
- Los ACL (Access Control List) : que nos permite definir los permisos de lectura-escritura-ejecución de nuestros bucket y objetos.
- Las URLs Firmadas : que nos permite acceder temporalmente a nuestros archivos protegidos, a través de una url que incluye una firma y un tiempo de expiración de los permisos. Éstas URLs las podremos generar con nuestro script, y llevarán como parámetro nuestra firma generada en tiempo de ejecución, que lleva implicita el tiempo de caducidad de la url.

La primera medida es aplicar permisos exclusivo de lectura para nuestro usuario (usando los ACLs) a todos los archivos que queramos proteger, para que sea imprescindible una validación al acceder a ellos.
Para generar nuestro script , necesitaremos echar mano de la clase Crypt/HMAC para construir el hash en sha1 que Amazon S3 requiere.
Lo primero será crear nuestra función para  generar nuestra firma:

PHP:
  1. require_once 'Crypt/HMAC.php';
  2. function hex2b64($str) {
  3. $raw = '';
  4. for ($i=0; $i <strlen($str); $i+=2) {
  5. $raw .= chr(hexdec(substr($str, $i, 2)));
  6. }
  7. return base64_encode($raw);
  8. }
  9. function makeSig($str) {
  10. $secretKey="Llave secreta que nos proporciona Amazon para nuestra cuenta";
  11. $hasher =& new Crypt_HMAC($secretKey, "sha1");
  12. $signature = hex2b64($hasher->hash($str));
  13. return($signature);
  14. }

Lo siguiente, será crearnos una función para construir nuestra URL firmada :

PHP:
  1. function getSignedURL($bucket, $key, $expires=120){
  2. $accessKeyId="accessKeyId que nos proporciona Amazon con nuestra cuenta";
  3. $expires = time() + $expires;
  4. $resource = $bucket."/".urlencode($key);
  5. $stringToSign = "GETnnn$expiresn/$resource";
  6. $signature = urlencode(makeSig($stringToSign));
  7. $signedUrl="http://s3.amazonaws.com/$resource?AWSAccessKeyId=$accessKeyId&Expires=$expires&Signature=$signature";
  8. return $signedUrl;
  9. }

Ésta función nos devolverá la url firmada, que estará disponible durante el tiempo (en segundos) que hayamos establecido en el parametro $expires (120seg por defecto)

Ahora ya sólamente nos falta un script que nos lance al contenido, pero que nos proteja de links externos a nuestro dominio.
Para ésto simplemente comprobaremos si existe el campo HTTP_REFERER en nuestra variable $_SERVER , que nos indicará que estamos accediendo a ésta url desde otra url de referencia , y que nuestro dominio (extraido desde $_SERVER['HTTP_HOST']) esté contenido en él.

PHP:
  1. function get_amazon_url($amazon_bucket,$amazon_object){
  2. if(isset($_SERVER['HTTP_REFERER']) && strstr($_SERVER['HTTP_REFERER'],$_SERVER['HTTP_HOST']))   {
  3. $url=getSignedURL($amazon_bucket,$amazon_object,60);
  4. header('Location:'.$url);
  5. }else{
  6. echo 'Éste contenido ha sido enlazado ilegalmente';
  7. }
  8. }

Al llamar a ésta función, seremos automáticamente redirigidos al contenido en amazon siempre que el link provenga desde nuestro mismo dominio. Por supuesto, si quisieramos permitir el acceso desde una determinada lista de dominios, simplemente tendríamos que modificar un poco la condición if , para que compruebe que cada uno de los dominios están incluido en el HTTP_REFERER.

Espero que sea útil.
Un Saludo !!

5 Responses

  1. Queli Coto Sep 15, 2008 -

    Genial!! parece sencillo de usar, estoy casi decidido a usar el sistema S3, mi primera idea era como copia de seguridad de mis datos pero tengo una duda y no sé si me las podrás aclarar.

    El S3 storage, es seguro en cuanto a bakups de datos?

  2. fillito Sep 15, 2008 -

    Hola Queli Coto.
    No se bien a lo que te refieres en cuanto a seguridad en backup de datos.

    S3 en una solución muy buena para tener tus backups, por disponibilidad y fiabilidad. Amazon replica todos los datos de manera interna, por lo que cuando tú subes un archivo, queda redundado varias veces como backup propio de Amazon. Por lo que puedes estar seguro de que tus datos no se perderán.

    No se si ésto responde a tu pregunta, pero no dudes en contactarme si puedo ayudarte en algo más.

    Saludos !

  3. leidy prado Jul 01, 2009 -

    Hola

    Necesito hosting para mi tienda virtual, desarrollada en asp clasico,commerce server 2002 y bd SQL server 2000, cual de los aws de amazon me serviría. ¿Puedo usar aws de Amazon desde cualquier parte del mundo?

    Saludos

  4. fillito Jul 01, 2009 -

    Hola Leidy prado

    Realmente no tengo ninguna experiencia con plataformas Windows sobre EC2 (siempre trabajo con máquinas Unix/Linux), pero sé que ya Amazon las soporta, por lo que montar un servidor con las características que citas sobre AWS es más que plausible. Pero te recomiendo que contactes al soporte de AWS o preguntes en el foro oficial de AWS.
    En cuanto tu pregunta de si puedes usar AWS desde cualquier parte del mundo. Si. Desde cualquier lugar que tengas completo acceso a internet, puedes controlar tu servicios AWS.

    Un saludo !

Trackbacks/Pingbacks

  1. Enlaces de la semana 8 — Viciao2k3

Leave a Reply