Comment restreindre le téléchargement des pièces jointes à un utilisateur spécifique?

12

J'ai un cas d'utilisation très spécifique où le site conçu pour un avocat et chacun de ses clients peut se connecter à sa propre `` page / portail spécifique '' (type de publication personnalisé) sans avoir accès à wp-admin, etc. (j'ai créé tous les pages de connexion / enregistrement / modification de profil dans le frontal). Dans cette page / portail, l'avocat laissera des messages et des fichiers à télécharger par le client , maintenant théoriquement, un client peut deviner (ou s'il a connaissance des fichiers d'un autre client) d'autres noms de fichiers et télécharger, créant ainsi un problème de confidentialité / sécurité / matériel confidentiel, etc.

Je suis à la recherche d'idées / concepts pour une solution, ma pensée initiale était d'avoir le lien de téléchargement vers un fichier download.php envoyant l'ID de pièce jointe, l'ID utilisateur, l'ID de page / portail et nonce et le traitement de l'autre côté. .

Qu'est-ce que tu penses? suis-je sur la bonne voie ou cette approche est-elle défectueuse?

Merci!

Amit
la source
Avez-vous trouvé une solution à cela?
brasofilo
@brasofilo, no ..
Amit

Réponses:

6

Ce qui doit arriver, c'est que vous devez proxy des demandes de téléchargement pour les types de fichiers que vous souhaitez via WordPress. Supposons que vous allez restreindre l'accès aux fichiers ".doc".

1. Définissez une variable de requête qui indique le fichier demandé

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

2. Mettez à jour .htaccess pour transférer les demandes de fichiers restreints vers WordPress

Cela capturera les demandes des fichiers que vous souhaitez restreindre et les renverra à WordPress en utilisant la variable de requête personnalisée ci-dessus. Insérez la règle suivante avant les RewriteCondlignes.

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

3. Capturez le nom de fichier demandé dans une variable de requête personnalisée; et vérifiez l'accès au fichier:

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 Cette solution fonctionne uniquement pour les installations sur site unique ! En effet, WordPress MU transfère déjà les demandes de fichiers téléchargées dans les sous-sites via wp-includes/ms-files.php. Il existe également une solution pour WordPress MU, mais elle est un peu plus impliquée.

Bendoh
la source
1
Salut, je ne vois pas que vous accrochez cette fonction à l'étape intercept_file_requestou qui est appelée n'importe où, comment cette fonction est-elle déclenchée?
Bobz
Bon point, il faut s'y accrocher wp, j'ai mis à jour l'exemple.
Bendoh
3

J'ai récemment eu un problème connexe et j'ai écrit cet article à ce sujet .

Je suppose que les téléchargements sont téléchargés via la gestion des médias de WordPress - ou sinon vous avez un ID de pièce jointe pour le téléchargement.

Aperçu de la solution

  • Rendre le répertoire de téléchargement «sécurisé» (dans ce sens, je veux simplement dire utiliser .htaccesspour bloquer toute tentative d'accéder directement aux fichiers dans le répertoire de téléchargement (ou un sous-répertoire de celui-ci) - par exemple via mysite.com/wp-content/uploads/conf/2012/09/myconfidentialfile.pdf)
  • Créez un lien de téléchargement comprenant l'ID de la pièce jointe - cela passe par WordPress pour vérifier l'autorisation de l'utilisateur à afficher la pièce jointe autorise / refuse l'accès.

Avertissements

  • Cela permet de .htaccessgarantir la sécurité . Si ce n'est pas disponible / activé (serveurs nginx par exemple), vous n'obtiendrez pas beaucoup de sécurité. Vous pouvez empêcher l'utilisateur de parcourir le répertoire uplods. Mais l'accès direct fonctionnera.
  • Comme ci-dessus. Cela ne doit pas être utilisé dans la distribution si vous avez besoin d'une sécurité absolue . C'est bien si votre configuration spécifique fonctionne - mais en général, cela ne peut pas être garanti. Mon article lié essaie en partie de résoudre ce problème.
  • Vous perdrez des vignettes . Le blocage de l'accès direct à un dossier ou sous-dossier signifie que les vignettes des fichiers de ce dossier ne peuvent pas être affichées. Mon article lié tente en partie de résoudre ce problème.

Bloquer l'accès direct

Pour ce faire, dans votre dossier de téléchargements (ou dans un sous-dossier - tous les documents confidentiels doivent résider, à n'importe quelle profondeur, à l'intérieur de ce dossier). Placez un .htaccessfichier avec les éléments suivants:

Order Deny,Allow
Deny from all

Dans ce qui suit, je suppose que vous joindrez des documents confidentiels au type de message «client». Tout média téléchargé sur la page de modification du client sera stocké dans le uploads/conf/dossier

La fonction pour configurer le répertoire des téléchargements protégés

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

Téléchargement de documents confidentiels

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

    }

Cela dit, le contenu téléchargé devrait être à l'intérieur uploads/confet essayer d'y accéder directement à l'aide de votre navigateur ne devrait pas fonctionner.

Téléchargement de contenu

C'est facile. L'URL de téléchargement peut être quelque chose www.site.com?wpse26342download=5(où 5 est l'ID de pièce jointe du contenu téléchargé). Nous l'utilisons pour identifier la pièce jointe, vérifier les autorisations de l'utilisateur actuel et lui permettre de télécharger.

Tout d'abord, configurez la variable de requête

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

Maintenant, configurez un écouteur pour (peut-être) déclencher le téléchargement ...

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

Commentaires finaux

Le code ci-dessus peut contenir des bugs / erreurs de syntaxe et n'est pas testé, et vous l'utilisez à vos risques et périls :).

L'URL de téléchargement peut être «améliorée» à l'aide de réécritures. Comme indiqué dans les commentaires, vous pouvez ajouter un espace vide à l' index.phpintérieur de chaque enfant du dossier protégé pour empêcher la navigation - mais cela devrait être empêché par les .htaccessrègles de toute façon.

Une méthode plus sûre serait de stocker les fichiers publics en dehors d'un répertoire public. Ou sur un service externe comme Amazon S3. Pour ce dernier, vous devrez générer une URL valide pour récupérer le fichier sur Amazon (en utilisant votre clé privée). Ces deux éléments nécessitent un certain niveau de confiance dans votre service hôte / tiers.

Je me méfierais de l'utilisation de plug-ins suggérant qu'ils offrent des «téléchargements protégés». Je n'en ai trouvé aucun qui offre une sécurité suffisante. Veuillez également ne pas mettre en garde contre cette solution - et j'accueillerais volontiers toutes suggestions ou critiques.

Stephen Harris
la source
1

Probablement, vous avez peut-être connu cette astuce, ce code vérifiera le nom d'utilisateur de l'utilisateur actuellement connecté et s'il correspond, il affichera le lien de téléchargement vers ce fichier, sinon il n'affichera rien.

voici le code:

<?php 
    global $current_user;
    get_currentuserinfo();

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

Cependant, ce ne sera pas une bonne approche, car les fichiers sont stockés sur des serveurs, toute personne disposant d'un lien peut télécharger ce fichier.

amit
la source
0

Je présume que ces informations sont confidentielles et, par conséquent, en plus de masquer les liens vers les fichiers, vous souhaiterez les rendre complètement inaccessibles à quiconque sur le Web, même s'ils devaient deviner l'URL, sauf si cet utilisateur a l'autorisation explicite de télécharger les fichiers.

Cherchez à stocker les fichiers sur Amazon S3 en toute sécurité, puis à fournir des URL pré-signées (limitées dans le temps) au fichier à condition que les contrôles de sécurité corrects aient été satisfaits (c'est-à-dire que l'utilisateur s'est connecté à votre site et qu'il est bien celui qu'il prétend être).

Il existe un très bon SDK AWS qui permet de le faire très simplement.

Ce que vous devrez rechercher est de savoir comment envoyer des fichiers téléchargés via l'interface de téléchargement WP dans S3 à la place, sinon créez votre propre téléchargeur .

Une autre option serait de trop regarder dans le code de WP e-commerce . Ils offrent un téléchargement sécurisé de fichiers logiciels (par exemple MP3). Je crois que les fichiers sont convertis en hachages avec une clé de cryptage générée par utilisateur lors de l'achat. Cela prendrait un peu de décryptage pour voir comment cela fonctionnait, mais le processus ne sera pas unique à ce plugin, donc d'autres exemples seront disponibles (quelque part).

deadlyhifi
la source
0

Je pense que le cryptage des fichiers est la voie à suivre comme la réponse ci-dessus. Il existe un plugin sur Wordpress.org qui vous permet de protéger les téléchargements. http://wordpress.org/extend/plugins/download-protect/ Vous pouvez également utiliser le service Amazon ou Google Drive. Il existe de nombreux services proposant également des téléchargements protégés, tels qu'une boîte de dépôt.

Chris
la source
la sécurité par l'obscurité est une mauvaise approche. n'importe qui pourra voir la requête http et obtenir l'url de cette façon.
mulllhausen