Wie kann ich den Download von Anhängen auf einen bestimmten Benutzer beschränken?

12

Ich habe einen ganz bestimmten Anwendungsfall, bei dem sich die für einen Anwalt erstellte Website und jeder seiner Kunden auf einer eigenen "bestimmten Seite / einem Portal" (benutzerdefinierter Beitragstyp) anmelden kann, ohne auf wp-admin usw. zugreifen zu können (ich habe die gesamte Website erstellt) Login / Registrieren / Profilbearbeitungsseiten im Frontend). Auf dieser Seite / auf diesem Portal hinterlässt der Anwalt Nachrichten und Dateien, die der Mandant herunterladen kann. Nun kann theoretisch ein Mandant andere Dateinamen erraten (oder wenn er Kenntnis von den Dateien eines anderen Mandanten hat) und diese herunterladen, wodurch ein Problem mit dem Datenschutz / der Sicherheit entsteht / vertrauliches Material etc.

Ich bin auf der Suche nach Ideen / Konzepten für eine Lösung. Mein erster Gedanke war, den Download-Link auf eine download.php-Datei zu verweisen, die die Anhangs-ID, die Benutzer-ID, die Seiten- / Portal-ID und die Nonce-ID sendet und auf der anderen Seite diese verarbeitet. .

was denkst du? bin ich auf dem richtigen Weg oder ist dieser Ansatz fehlerhaft?

Vielen Dank!

Amit
quelle
Haben Sie eine Lösung dafür gefunden?
Brasofilo
@ brasofilo, no ..
Amit

Antworten:

6

Was passieren muss, ist, dass Sie Download-Anfragen für die gewünschten Dateitypen über WordPress per Proxy senden müssen. Nehmen wir an, Sie beschränken den Zugriff auf ".doc" -Dateien.

1. Definieren Sie eine Abfragevariable, die die angeforderte Datei angibt

function add_get_file_query_var( $vars ) {
    $vars[] = 'get_file';
    return $vars;
}
add_filter( 'query_vars', 'add_get_file_query_var' );

2. Aktualisieren Sie .htaccess, um Anforderungen für eingeschränkte Dateien an WordPress weiterzuleiten

Dadurch werden Anforderungen an die Dateien erfasst, die Sie einschränken möchten, und sie werden mithilfe der oben angegebenen benutzerdefinierten Abfragevariablen an WordPress zurückgesendet. Fügen Sie die folgende Regel vor den RewriteCondZeilen ein.

RewriteRule ^wp-content/uploads/(.*\.docx)$ /index.php?get_file=$1

3. Erfassen Sie den angeforderten Dateinamen in der benutzerdefinierten Abfragevariablen. und überprüfe den Zugriff auf die Datei:

function intercept_file_request( $wp ) {
    if( !isset( $wp->query_vars['get_file'] ) )
        return;

    global $wpdb, $current_user;

    // Find attachment entry for this file in the database:
    $query = $wpdb->prepare("SELECT ID FROM {$wpdb->posts} WHERE guid='%s'", $_SERVER['REQUEST_URI'] );
    $attachment_id = $wpdb->get_var( $query );

    // No attachment found. 404 error.  
    if( !$attachment_id ) {
        $wp->query_vars['error'] = '404';
        return;
    }

    // Get post from database 
    $file_post = get_post( $attachment_id );
    $file_path = get_attached_file( $attachment_id );

    if( !$file_post || !$file_path || !file_exists( $file_path ) ) {
        $wp->query_vars['error'] = '404';
        return;
    }

    // Logic for validating current user's access to this file...
    // Option A: check for user capability
    if( !current_user_can( 'required_capability' ) ) {
        $wp->query_vars['error'] = '404';
        return;
    }

    // Option B: check against current user
    if( $current_user->user_login == "authorized_user" ) {
        $wp->query_vars['error'] = '404';
        return;
    }

    // Everything checks out, user can see this file. Simulate headers and go:
    header( 'Content-Type: ' . $file_post->post_mime_type );
    header( 'Content-Dispositon: attachment; filename="'. basename( $file_path ) .'"' );
    header( 'Content-Length: ' . filesize( $file_path ) );

    echo file_get_contents( $file_path );
    die(0);
}
add_action( 'wp', 'intercept_file_request' );

NB Diese Lösung funktioniert für Single-Site installiert nur ! Dies liegt daran, dass WordPress MU bereits hochgeladene Dateianfragen in Unterseiten weiterleitet wp-includes/ms-files.php. Es gibt auch eine Lösung für WordPress MU, aber es ist ein bisschen komplizierter.

Bendoh
quelle
Hallo zusammen, ich sehe nicht, dass Sie diese Funktion in Schritt einbinden intercept_file_requestoder dass sie irgendwo aufgerufen wird. Wie wird diese Funktion ausgelöst?
Bobz
Guter Punkt, es sollte angebunden sein wp, ich habe das Beispiel aktualisiert.
Bendoh
3

Ich habe kürzlich ein ähnliches Problem gehabt und diesen Artikel darüber geschrieben .

Ich gehe davon aus, dass die Downloads über das Media Handling von WordPress hochgeladen werden - oder Sie haben eine Anhang-ID für den Download.

Umriss der Lösung

  • Das Upload-Verzeichnis 'sicher' machen (in diesem Sinne meine ich damit nur den .htaccessVersuch, den direkten Zugriff auf Dateien im Upload-Verzeichnis (oder einem Unterverzeichnis davon) zu blockieren - z. B. über mysite.com/wp-content/uploads/conf/2012/09/myconfidentialfile.pdf)
  • Erstellen Sie einen Download-Link mit der ID des Anhangs. Hiermit überprüfen Sie in WordPress, ob der Benutzer zum Anzeigen des Anhangs berechtigt ist, und verweigern den Zugriff.

Vorbehalte

  • Dies dient der .htaccessSicherheit . Wenn dies nicht verfügbar / aktiviert ist (z. B. Nginx-Server), erhalten Sie nicht viel Sicherheit. Sie können verhindern, dass der Benutzer das Verzeichnis uplods durchsucht . Aber der direkte Zugriff wird funktionieren.
  • Wie oben Dies sollte nicht in der Distribution verwendet werden, wenn Sie absolute Sicherheit benötigen . Es ist in Ordnung, wenn Ihr spezielles Setup funktioniert - aber im Allgemeinen kann dies nicht garantiert werden. Mein verlinkter Artikel versucht zum Teil, dies zu beheben.
  • Sie werden Thumbnails verlieren . Wenn Sie den direkten Zugriff auf einen Ordner oder Unterordner blockieren, können Miniaturansichten der Dateien in diesem Ordner nicht angezeigt werden. Mein verlinkter Artikel versucht teilweise, dies zu beheben.

Direktzugriff sperren

Zu diesem Zweck muss sich das gesamte vertrauliche Material in Ihrem Upload-Ordner (oder einem Unterordner) in einer beliebigen Tiefe in diesem Ordner befinden. Legen Sie eine .htaccessDatei mit den folgenden Eigenschaften ab:

Order Deny,Allow
Deny from all

Im Folgenden gehe ich davon aus, dass Sie vertrauliches Material an den Beitragstyp "Client" anhängen. Alle auf der Client-Bearbeitungsseite hochgeladenen Medien werden im uploads/conf/Ordner gespeichert

Die Funktion zum Einrichten des geschützten Upload-Verzeichnisses

function wpse26342_setup_uploads_dir(){

    $wp_upload_dir = wp_upload_dir();
    $protected_folder = trailingslashit($wp_upload_dir['basedir']) . 'conf';    

    // Do not allow direct access to files in protected folder
    // Add rules to /uploads/conf/.htacess
    $rules = "Order Deny,Allow\n";
    $rules .= "Deny from all";

    if( ! @file_get_contents( trailingslashit($protected_folder).'.htaccess' ) ) {
            //Protected directory doesn't exist - create it.
        wp_mkdir_p( $protected_folder);
    }
    @file_put_contents( trailingslashit($protected_folder).'.htaccess', $rules );

     //Optional add blank index.php file to each sub-folder of protected folder.
}

Hochladen von vertraulichem Material

   /**
    * Checks if content is being uploaded on the client edit-page
    * Calls a function to ensure the protected file has the .htaccess rules
    * Filters the upload destination to the protected file
    */
    add_action('admin_init', 'wpse26342_maybe_change_uploads_dir', 999);
    function wpse26342_maybe_change_uploads_dir() {
        global $pagenow;

        if ( ! empty( $_POST['post_id'] ) && ( 'async-upload.php' == $pagenow || 'media-upload.php' == $pagenow ) ) {
                if ( 'client' == get_post_type( $_REQUEST['post_id'] ) ) {
                       //Uploading content on the edit-client page

                       //Make sure uploads directory is protected
                       wpse26342_setup_uploads_dir();

                       //Change the destination of the uploaded file to protected directory.
                       add_filter( 'upload_dir', 'wpse26342_set_uploads_dir' );
                }
        }

    }

Danach sollte sich der hochgeladene Inhalt in uploads/confIhrem Browser befinden und der Versuch, mit Ihrem Browser direkt darauf zuzugreifen, sollte nicht funktionieren.

Herunterladen von Inhalten

Das ist einfach. Die Download-URL kann etwas sein www.site.com?wpse26342download=5(wobei 5 die Anhang-ID des hochgeladenen Inhalts ist). Wir verwenden dies, um den Anhang zu identifizieren, die Berechtigungen des aktuellen Benutzers zu überprüfen und ihnen das Herunterladen zu ermöglichen.

Richten Sie zunächst die Abfragevariable ein

/**
 * Adds wpse26342download to the public query variables
 * This is used for the public download url
 */
add_action('query_vars','wpse26342_add_download_qv');
function wpse26342_add_download_qv( $qv ){
    $qv[] = 'wpse26342download';
    return $qv;
}}

Richten Sie nun einen Listener ein, um (vielleicht) den Download auszulösen ...

add_action('request','wpse26342_trigger_download');
function wpse26342_trigger_download( $query_vars ){

        //Only continue if the query variable set and user is logged in...
    if( !empty($query_vars['wpse26342download']) && is_user_logged_in() ){

        //Get attachment download path
        $attachment = (int) $query_vars['wpse26342download'];
        $file = get_attached_file($attachment);

        if( !$file )
             return;

        //Check if user has permission to download. If not abort.       
        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();
    }
    return $query_vars;
}

Letzte Kommentare

Der obige Code kann Fehler / Syntaxfehler enthalten und ist ungetestet. Die Verwendung erfolgt auf eigenes Risiko :).

Die Download-URL kann durch Umschreiben "verschönert" werden. Wie in den Kommentaren angegeben, können Sie index.phpin jedes untergeordnete Element des geschützten Ordners ein Leerzeichen einfügen, um das Durchsuchen zu verhindern. Dies sollte jedoch durch die .htaccessRegeln verhindert werden.

Eine sicherere Methode wäre, die öffentlichen Dateien außerhalb eines öffentlichen Verzeichnisses zu speichern. Oder über einen externen Dienst wie Amazon S3. Für letzteres müssen Sie eine gültige URL generieren, um die Datei von Amazon abzurufen (mit Ihrem privaten Schlüssel). Beides setzt ein gewisses Maß an Vertrauen in Ihren Host / Third Party Service voraus.

Ich wäre vorsichtig bei der Verwendung von Plug-Ins, die "geschützte Downloads" anbieten. Ich habe keine gefunden, die ausreichend Sicherheit bieten. Bitte beachten Sie auch die Einschränkungen dieser Lösung - und ich würde Anregungen und Kritik begrüßen.

Stephen Harris
quelle
1

Möglicherweise haben Sie diesen Trick gekannt. Dieser Code prüft, ob der Benutzername des aktuell angemeldeten Benutzers übereinstimmt. Wenn er übereinstimmt, wird der Download-Link zu dieser Datei angezeigt, andernfalls wird nichts angezeigt.

Hier ist der Code:

<?php 
    global $current_user;
    get_currentuserinfo();

    if ( 'username' == $current_user->user_login ) {
        echo 'Download Link';
    } else {
        // nothing
    }
?>

Dies ist jedoch kein guter Ansatz, da Dateien auf Servern gespeichert werden und jeder mit einem Link diese Datei herunterladen kann.

amit
quelle
0

Ich gehe davon aus, dass diese Informationen vertraulich sind und dass Sie daher nicht nur die Links zu den Dateien verbergen möchten, sondern diese auch für jeden im Web unzugänglich machen möchten, selbst wenn er die URL erraten sollte, es sei denn, dieser Benutzer hat die ausdrückliche Erlaubnis zum Herunterladen die Dateien.

Überprüfen Sie, ob die Dateien auf Amazon S3 sicher gespeichert sind , und geben Sie dann vorab signierte (zeitlich begrenzte) URLs für die Datei an, sofern die korrekten Sicherheitsüberprüfungen erfüllt wurden (dh der Benutzer hat sich auf Ihrer Website angemeldet und weiß, wer er ist).

Es gibt ein sehr gutes AWS SDK , mit dem dies sehr einfach möglich ist.

Was Sie erforschen müssen, ist, wie Sie Dateien, die über die WP-Upload-Schnittstelle hochgeladen wurden, an S3 senden oder alternativ Ihren eigenen Uploader erstellen können .

Eine andere Möglichkeit wäre es, in den Code von WP E-Commerce zu schauen . Sie bieten einen sicheren Download von Software-Dateien (zB MP3s). Ich glaube, die Dateien werden mit einem Verschlüsselungsschlüssel, der pro Benutzer beim Kauf generiert wird, in Hashes umgewandelt. Dies würde eine gewisse Entschlüsselung erfordern, um zu sehen, wie es funktioniert, aber der Prozess wird nicht für dieses Plugin spezifisch sein, so dass (irgendwo) andere Beispiele verfügbar sein werden.

tödliche Hifi
quelle
0

Ich denke, die Verschlüsselung der Dateien ist der richtige Weg, wie die obige Antwort. Auf Wordpress.org gibt es ein Plugin, mit dem Sie die Downloads schützen können. http://wordpress.org/extend/plugins/download-protect/ Sie können auch den Amazon-Dienst oder Google Drive verwenden. Es gibt viele Dienste, die geschützte Downloads anbieten, wie zum Beispiel auch Dropbox.

Chris
quelle
Sicherheit durch Dunkelheit ist ein schlechter Ansatz. Jeder kann die http-Anfrage sehen und die URL auf diese Weise abrufen.
Mulllhausen