Permissões para servir arquivos temporários

8

Eu tenho um sistema (aplicativo baseado na Web) que extrai anexos de arquivos de um sistema de terceiros via SOAP. Estes, por sua vez, são criados em nosso sistema como arquivos em um diretório.

Quando um usuário do sistema (autenticado por meio do ldap) faz um pedido ao meu aplicativo para recuperar um destes anexos:

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.  

Primeiro, essa é uma boa abordagem?

Existe uma maneira melhor de servir arquivos que não residirão no servidor muito após o download do anexo (o trabalho cron limpará o diretório de vez em quando)?

Em segundo lugar, existe uma maneira de eu servir arquivos através do apache sem armazená-los na raiz da web?

Em terceiro lugar, como impor permissões nesses arquivos para que nenhum usuário possa baixar qualquer anexo?

Nossa instalação:

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

EDIT: O código para veicular o anexo, caso alguém esteja curioso.

    <?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
fonte
Provavelmente isso pertence ao StackOverflow
John Conde

Respostas:

2

Primeiro, essa é uma boa abordagem?

Parece bom para mim. Apenas certifique-se de autenticar o usuário antes de passar por tudo isso.

Existe uma maneira melhor de servir arquivos que não residirão no servidor muito após o download do anexo (o trabalho cron limpará o diretório de vez em quando)?

Em segundo lugar, existe uma maneira de eu servir arquivos através do apache sem armazená-los na raiz da web?

Coloque os arquivos fora da raiz da web. Em seguida, usando PHP, passe o arquivo por um script. Dessa forma, ninguém pode vincular o arquivo diretamente e ignorar seus controles. (Naturalmente, verifique se o script que faz isso somente após verificar o usuário tem permissão para recuperar esse arquivo).

Exemplo de PHP:

<?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;
?>

Em terceiro lugar, como impor permissões nesses arquivos para que nenhum usuário possa baixar qualquer anexo?

Faça com que os usuários efetuem login para recuperar seus arquivos. Em seguida, você pode definir uma variável de sessão identificando-as como tendo permissão para fazer o download. Verifique se os scripts os autenticam em todas as páginas deste processo.

John Conde
fonte
Esta é uma ótima explicação! Obrigado. Com base na sua sugestão, seria melhor armazenar esses arquivos fora da raiz da web, dessa forma, não preciso me preocupar com o link / acesso direto aos arquivos e apenas servi-los com base em uma página php com lógica semelhante à acima para verificar a autenticação do usuário antes de enviar o arquivo. Cheers
Chris
@ John Conde Notei o tipo de conteúdo específico como "application / octet-stream", então isso funcionará com qualquer tipo de arquivo? Isso não funciona, nem especificar o tipo mime de conteúdo. Por exemplo, eu tenho um pdf sentado lá que eu posso puxar e sei que é um bom pdf, mas quando eu o servo através da moda que você apresenta, recebo "O documento de texto sem formatação do tipo de arquivo (texto / sem formatação) não é suportado".
Chris
Eu acredito que sim. Caso contrário, tudo o que você precisa fazer é alterar essa parte para o tipo mime adequado. Mas tenho certeza de que funcionará para qualquer tipo de arquivo.
John Conde
Por alguma razão, posso ir para uploads / filename.pdf, mas o script php não pode servir o arquivo usando application / octet-stream ou application / pdf para este caso específico.
Chris
Que erro você recebe? Verifique se o script pode encontrar o arquivo, pois o caminho pode estar incorreto em algum lugar.
John Conde