Permisos para servir archivos temporales

8

Tengo un sistema (aplicación basada en web) que extrae archivos adjuntos de un sistema de terceros a través de SOAP. Estos a su vez se crean en nuestro sistema como archivos en un directorio.

Cuando un usuario del sistema (autenticado a través de ldap) realiza una solicitud a mi aplicación para recuperar uno de estos archivos adjuntos:

1. I request it via soap
2. Process the response to build the file on our system
3. Redirect user to the location so they can download the file.  

En primer lugar, ¿es este un buen enfoque?

¿Hay una mejor manera de servir archivos que no residirán en el servidor mucho después de la descarga del archivo adjunto (el trabajo cron limpiará el directorio de vez en cuando)?

En segundo lugar, ¿hay alguna forma en que pueda servir archivos a través de apache sin almacenarlos en la raíz web?

En tercer lugar, ¿cómo hago cumplir los permisos en estos archivos para que no cualquier usuario pueda descargar cualquier archivo adjunto?

Nuestra Configuración:

linux
apache
php - soap libraries for communication 
seperate LDAP for authentication
3rd party soap server (where attachments come from) 

EDITAR: El código para servir el archivo adjunto en caso de que alguien tenga curiosidad.

    <?php 

ini_set('display_errors',1);
error_reporting(E_ALL|E_STRICT);

//require global definitions 
require_once("includes/globals.php"); 
//validate the user before continuing 
isValidUser(); 
$subTitle = "Attachment";   
$attachmentPath = "/var/www/html/DEVELOPMENT/serviceNow/selfService/uploads/";
if(isset($_GET['id']) and !empty($_GET['id'])){
    //first lookup attachment meta information 
    $a = new Attachment(); 
    $attachment = $a->get($_GET['id']); 
    //filename will be original file name with user name.n prepended 
    $fileName = $attachmentPath.$_SESSION['nameN'].'-'.$attachment->file_name; 
    //instantiate new attachmentDownload and query for attachment chunks 
    $a = new AttachmentDownload(); 
    $chunks= $a->getRecords(array('sys_attachment'=>$_GET['id'], '__order_by'=>'position')); 


    $fh = fopen($fileName.'.gz','w');                                                      
    // read and base64 encode file contents 
    foreach($chunks as $chunk){
            fwrite($fh, base64_decode($chunk->data));   
    }
    fclose($fh);

    //open up filename for writing 
    $fh = fopen($fileName,'w');     
    //open up filename.gz for extraction                                
    $zd = gzopen($fileName.'.gz', "r");
    //iterate over file and write contents 
    while (!feof($zd)) {
            fwrite($fh, gzread($zd, 60*57));    
    }
    fclose($fh); 
    gzclose($zd);
    unlink($fileName.'.gz'); 
    $info = pathinfo($fileName); 

    header('Content-Description: File Transfer');
    header('Content-Type: '.Mimetypes::get($info['extension']));
    header('Content-Disposition: attachment; filename=' . basename($fileName));
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    header('Content-Length: ' . filesize($fileName));
    ob_clean();
    flush();
    readfile($fileName);
    exit();
}else{
    header("location: ".$links['status']."?".urlencode("item=incident&action=view&status=-1&place=".$links['home']));   
}


?>
Chris
fuente
Esto probablemente pertenece a StackOverflow
John Conde

Respuestas:

2

En primer lugar, ¿es este un buen enfoque?

Suena bien para mi. Solo asegúrese de autenticar al usuario antes de pasar por todo eso.

¿Hay una mejor manera de servir archivos que no residirán en el servidor mucho después de la descarga del archivo adjunto (el trabajo cron limpiará el directorio de vez en cuando)?

En segundo lugar, ¿hay alguna forma en que pueda servir archivos a través de apache sin almacenarlos en la raíz web?

Ponga los archivos fuera del webroot. Luego, usando PHP, pasa el archivo a través de un script. De esa manera, nadie puede vincular el archivo directamente y omitir sus controles. (Naturalmente, asegúrese de que el script que hace esto solo después de verificar que el usuario tenga permiso para recuperar ese archivo).

PHP de muestra:

<?php
    if (!isset($_SESSION['authenticated']))
    {
        exit;
    }
    $file = '/path/to/file/outside/www/secret.pdf';

    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename=' . basename($file));
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    ob_clean();
    flush();
    readfile($file);
    exit;
?>

En tercer lugar, ¿cómo hago cumplir los permisos en estos archivos para que no cualquier usuario pueda descargar cualquier archivo adjunto?

Haga que los usuarios inicien sesión para recuperar sus archivos. Luego, puede establecer una variable de sesión que los identifique como permitidos para descargar. Asegúrese de que sus scripts los autentiquen en cada página de este proceso.

John Conde
fuente
Esta es una gran explicación! Gracias. De acuerdo con su sugerencia, sería mejor almacenar estos archivos fuera del raíz web de esa manera, no tengo que preocuparme por el enlace directo / acceso a los archivos y simplemente servirlos en base a una página php con una lógica similar a la anterior para verificar el autenticación del usuario antes de servir el archivo. Saludos
Chris
@ John Conde ¿Noté un tipo de contenido específico como "aplicación / octeto-flujo", por lo que esto funcionará con cualquier tipo de archivo? Esto no funciona, ni tampoco especifica el contenido tipo mime. Por ejemplo, tengo un pdf allí que puedo extraer y sé que es un buen pdf, pero cuando lo entrego a través de la moda que presenta, recibo "No se admite el documento de texto sin formato de tipo de archivo (texto / sin formato)".
Chris
Eso creo. Si no es así, todo lo que necesita hacer es cambiar esa parte al tipo mime adecuado. Pero estoy bastante seguro de que funcionará para cualquier tipo de archivo.
John Conde
Por alguna razón, puedo ir a uploads / filename.pdf pero el script php no puede servir el archivo usando application / octet-stream o application / pdf para este caso específico.
Chris
¿Qué error obtienes? Verifique que el script pueda encontrar el archivo ya que la ruta puede ser incorrecta en alguna parte.
John Conde