Come limitare il download degli allegati a un utente specifico?


12

Ho un caso d'uso molto specifico in cui il sito creato per un avvocato e ciascuno dei suoi clienti può accedere alla propria "pagina / portale" specifica (tipo di post personalizzato) senza la possibilità di accedere a wp-admin ecc. (Ho creato tutti i pagine di login / register / modifica profilo nel front-end). In questa pagina / portale, l'avvocato lascerà messaggi e file che il client può scaricare , ora teoricamente parlando, un cliente può indovinare (o se ha conoscenza dei file di un altro cliente) altri nomi di file e scaricare, creando così un problema con la privacy / sicurezza / materiale riservato ecc.

Sto cercando idee / concetti per una soluzione, il mio pensiero iniziale era che il link per il download puntasse ad alcuni download.php inviando l'id allegato, l'ID utente, l'id pagina / portale e nonce e dall'altra parte elaborandolo. .

cosa pensi? sono sulla buona strada o questo approccio è imperfetto?

Grazie!


Hai trovato una soluzione per questo?
brasofilo,

@brasofilo, no ..
Amit

Risposte:


6

Ciò che deve accadere è che è necessario eseguire il proxy delle richieste di download per i tipi di file desiderati tramite WordPress. Supponiamo che limiterai l'accesso ai file ".doc".

1. Definire una variabile di query che indica il file richiesto

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

2. Aggiorna .htaccess per inoltrare le richieste di file con restrizioni a WordPress

Questo acquisirà le richieste ai file che vuoi limitare e le rimanderà a WordPress usando la variabile di query personalizzata sopra. Inserisci la seguente regola prima delle RewriteCondrighe.

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

3. Cattura il nome del file richiesto nella variabile di query personalizzata; e verifica l'accesso al file:

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 Questa soluzione funziona solo per installazioni su un unico sito ! Questo perché WordPress MU inoltra già richieste di file caricate nei siti secondari tramite wp-includes/ms-files.php. C'è una soluzione anche per WordPress MU, ma è un po 'più coinvolta.


1
Salve, non vedo che si aggancia questa funzione al passaggio intercept_file_requesto che viene chiamata da nessuna parte, come viene attivata quella funzione?
Bobz,

Buon punto, dovrebbe essere agganciato wp, ho aggiornato l'esempio.
Bendoh,

3

Di recente ho avuto un problema correlato e ho scritto questo articolo a riguardo .

Presumo che i download vengano caricati tramite la gestione dei file multimediali di WordPress o altrimenti si dispone di un ID allegato per il download.

Schema di soluzione

  • Rendi la directory dei caricamenti "sicura" (In questo senso intendo solo usare .htaccessper bloccare qualsiasi tentativo di accedere direttamente ai file nella directory dei caricamenti (o in una sua sottodirectory) - ad es. Via mysite.com/wp-content/uploads/conf/2012/09/myconfidentialfile.pdf)
  • Crea un collegamento per il download che includa l'ID allegato: questo passa attraverso WordPress per verificare l'autorizzazione dell'utente a visualizzare l'allegato consente / nega l'accesso.

Avvertenze

  • Questo utilizza .htaccessper fornire sicurezza . Se questo non è disponibile / attivato (ad esempio server nginx), non otterrai molta sicurezza. È possibile impedire all'utente la navigazione nella directory degli uplods. Ma l'accesso diretto funzionerà.
  • Come sopra. Questo non dovrebbe essere usato nella distribuzione se si necessita di sicurezza assoluta . Va bene se la tua configurazione specifica funziona, ma in generale non può essere garantita. Il mio articolo collegato sta in parte cercando di risolvere questo problema.
  • Perderai le anteprime . Il blocco dell'accesso diretto a una cartella o sottocartella comporterà l'impossibilità di visualizzare le anteprime dei file in quella cartella. Il mio articolo collegato sta in parte tentando di risolvere questo problema.

Blocco dell'accesso diretto

Per fare ciò nella cartella dei caricamenti (o in una sottocartella, tutto il materiale riservato deve risiedere, a qualsiasi profondità, all'interno di questa cartella). Inserire un .htaccessfile con il seguente:

Order Deny,Allow
Deny from all

Di seguito suppongo che allegherai materiale riservato per inserire il tipo "client". Qualsiasi supporto caricato sulla pagina di modifica del client verrà archiviato nella uploads/conf/cartella

La funzione per impostare la directory di upload protetta

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.
}

Caricamento materiale riservato

   /**
    * 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' );
                }
        }

    }

Fatto ciò, il contenuto caricato dovrebbe trovarsi all'interno uploads/confe tentare di accedervi direttamente utilizzando il browser non dovrebbe funzionare.

Download di contenuti

Questo è facile. L'URL di download può essere qualcosa www.site.com?wpse26342download=5(dove 5 è l'ID allegato del contenuto caricato). Usiamo questo per identificare l'allegato, controllare le autorizzazioni dell'utente corrente e consentire loro di scaricare.

Innanzitutto, imposta la variabile di query

/**
 * 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;
}}

Ora imposta un ascoltatore per (forse) attivare il download ...

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

Commenti finali

Il codice sopra può contenere bug / errori di sintassi ed è non testato e lo si utilizza a proprio rischio :).

L'URL di download può essere "preimpostato" utilizzando riscritture. Come indicato nei commenti, è possibile aggiungere uno spazio vuoto index.phpall'interno di ogni figlio della cartella protetta per impedire la navigazione, ma ciò dovrebbe essere comunque impedito dalle .htaccessregole.

Un metodo più sicuro sarebbe quello di archiviare i file pubblici al di fuori di una directory pubblica. O su un servizio esterno come Amazon S3. Per quest'ultimo dovrai generare un URL valido per recuperare il file da Amazon (usando la tua chiave privata). Entrambi richiedono un certo livello di fiducia nel servizio Host / di terze parti.

Sarei diffidente sull'uso di eventuali plug-in che suggeriscono che offrono "download protetti". Non ne ho trovato nessuno che fornisca una sicurezza sufficiente. Per favore, non le avvertenze di questa soluzione - e sarei lieto di ricevere suggerimenti o critiche.


1

Probabilmente, potresti aver conosciuto questo trucco, questo codice controllerà il nome utente dell'utente attualmente connesso e se corrisponde mostrerà il link per il download a quel file, altrimenti non mostrerà nulla.

ecco il codice:

<?php 
    global $current_user;
    get_currentuserinfo();

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

Tuttavia, questo non sarà un buon approccio, poiché i file sono archiviati sui server, chiunque abbia un collegamento può scaricare quel file.


0

Presumo che queste informazioni siano confidenziali e quindi oltre a nascondere i collegamenti ai file, vorrai renderli effettivamente inaccessibili completamente a chiunque sul Web, anche se dovessero indovinare l'URL, a meno che l'utente non disponga dell'autorizzazione esplicita per il download i file.

Cerca di archiviare i file su Amazon S3 in modo sicuro e quindi di fornire URL pre-firmati (tempo limitato) al file, a condizione che siano stati soddisfatti i controlli di sicurezza corretti (ovvero, l'utente ha effettuato l'accesso al tuo sito ed è chi dice di essere).

Esiste un ottimo SDK AWS che lo rende molto semplice.

Ciò di cui hai bisogno per ricercare è invece come inviare file caricati tramite l'interfaccia di caricamento WP in S3, in alternativa crea il tuo uploader .

Un'altra opzione potrebbe essere quella di esaminare il codice dell'e-commerce di WP . Offrono il download sicuro di file software (ad es. MP3). Credo che i file vengano convertiti in hash con una chiave di crittografia generata per utente al momento dell'acquisto. Ciò richiederebbe un po 'di decifrazione per vedere come ha funzionato, ma il processo non sarà univoco per questo plugin, quindi saranno disponibili altri esempi (da qualche parte).


0

Penso che la crittografia dei file sia la strada da percorrere come la risposta sopra. C'è un plugin su Wordpress.org che ti consente di proteggere i download. http://wordpress.org/extend/plugins/download-protect/ Puoi utilizzare anche il servizio amazzoni o Google Drive. Esistono molti servizi che offrono download protetti come anche la casella di riepilogo.


la sicurezza attraverso l'oscurità è un cattivo approccio. chiunque sarà in grado di vedere la richiesta http e ottenere l'URL in questo modo.
Mulllhausen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.