Berechtigungen zum Bereitstellen temporärer Dateien

8

Ich habe ein System (webbasierte Anwendung), das Dateianhänge von einem System eines Drittanbieters über SOAP abruft. Diese werden wiederum auf unserem System als Dateien in einem Verzeichnis erstellt.

Wenn ein Benutzer des Systems (authentifiziert durch ldap) eine Anfrage an meine Anwendung stellt, um einen dieser Anhänge abzurufen:

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.  

Ist dies zunächst einmal ein guter Ansatz?

Gibt es eine bessere Möglichkeit, Dateien bereitzustellen, die sich nicht viel nach dem Herunterladen des Anhangs auf dem Server befinden (der Cron-Job bereinigt das Verzeichnis von Zeit zu Zeit)?

Zweitens, gibt es eine Möglichkeit, Dateien über Apache bereitzustellen, ohne sie im Webstamm zu speichern?

Drittens, wie erzwinge ich Berechtigungen für diese Dateien, damit nicht jeder Benutzer nur einen Anhang herunterladen kann?

Unser Setup:

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

BEARBEITEN: Der Code für den Anhang, falls jemand neugierig ist.

    <?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
quelle
Dies gehört wahrscheinlich auf StackOverflow
John Conde

Antworten:

2

Ist dies zunächst einmal ein guter Ansatz?

Hört sich gut an. Stellen Sie einfach sicher, dass Sie den Benutzer authentifizieren, bevor Sie dies alles durchgehen.

Gibt es eine bessere Möglichkeit, Dateien bereitzustellen, die sich nicht viel nach dem Herunterladen des Anhangs auf dem Server befinden (der Cron-Job bereinigt das Verzeichnis von Zeit zu Zeit)?

Zweitens, gibt es eine Möglichkeit, Dateien über Apache bereitzustellen, ohne sie im Webstamm zu speichern?

Legen Sie die Dateien außerhalb der Webroot ab. Übergeben Sie dann mit PHP die Datei durch ein Skript. Auf diese Weise kann niemand direkt auf die Datei verlinken und Ihre Steuerelemente umgehen. (Stellen Sie natürlich sicher, dass das Skript, das dies tut, erst nach Überprüfung des Benutzers über die Berechtigung zum Abrufen dieser Datei verfügt.)

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

Drittens, wie erzwinge ich Berechtigungen für diese Dateien, damit nicht jeder Benutzer nur einen Anhang herunterladen kann?

Lassen Sie die Benutzer sich anmelden, um ihre Dateien abzurufen. Anschließend können Sie eine Sitzungsvariable festlegen, die angibt, dass sie heruntergeladen werden dürfen. Stellen Sie sicher, dass Ihre Skripte sie auf jeder Seite dieses Prozesses authentifizieren.

John Conde
quelle
Das ist eine großartige Erklärung! Vielen Dank. Aufgrund Ihres Vorschlags ist es besser, diese Dateien außerhalb der Webroot zu speichern. Auf diese Weise muss ich mich nicht um den direkten Link / Zugriff auf die Dateien kümmern und sie lediglich auf der Grundlage einer PHP-Seite mit einer ähnlichen Logik wie oben bereitstellen, um die zu überprüfen Authentifizierung des Benutzers vor dem Bereitstellen der Datei. Prost
Chris
@ John Conde Ich habe festgestellt, dass der Inhaltstyp spezifisch als "application / octet-stream" ist, sodass dies mit jedem Dateityp funktioniert. Dies funktioniert nicht und es wird auch kein MIME-Typ für den Inhalt angegeben. Zum Beispiel habe ich dort ein PDF, das ich abrufen kann und weiß, dass es ein gutes PDF ist, aber wenn ich es über die von Ihnen präsentierte Mode bereitstelle, erhalte ich "Dateityp Nur-Text-Dokument (Text / Nur-Schrift) wird nicht unterstützt".
Chris
Ich glaube schon. Wenn dies nicht der Fall ist, müssen Sie diesen Teil nur in den richtigen MIME-Typ ändern. Aber ich bin mir ziemlich sicher, dass das für jeden Dateityp funktioniert.
John Conde
Aus irgendeinem Grund kann ich zu uploads / filename.pdf gehen, aber das PHP-Skript kann die Datei für diesen speziellen Fall weder mit application / octet-stream noch mit application / pdf bereitstellen.
Chris
Welchen Fehler bekommen Sie? Stellen Sie sicher, dass das Skript die Datei finden kann, da der Pfad möglicherweise irgendwo falsch ist.
John Conde