¿Cómo restringir la descarga de archivos adjuntos a un usuario específico?

12

Tengo un caso de uso muy específico en el que el sitio creado para un abogado y cada uno de sus clientes pueden iniciar sesión en su 'página / portal específico' (tipo de publicación personalizada) sin la capacidad de acceder a wp-admin, etc. creó todas las páginas de inicio de sesión / registro / edición de perfil en el extremo frontal). En esta página / portal, el abogado dejará mensajes y archivos para que el cliente los descargue , ahora teóricamente hablando, un cliente puede adivinar (o si tiene conocimiento de los archivos de otro cliente) otros nombres de archivos y descargarlos. crear un problema con la privacidad / seguridad / material confidencial, etc.

Estoy buscando ideas / conceptos para una solución, lo primero que pensé fue que el enlace de descarga apuntara a algún download.php que enviara el ID del archivo adjunto, el ID del usuario, el ID de la página / portal y el otro lado. procesando eso ..

¿qué te parece? ¿Estoy en el camino correcto o este enfoque es defectuoso?

¡Gracias!

    
pregunta Amit 19.08.2011 - 16:22

5 respuestas

5

Lo que debe suceder es que debe realizar solicitudes de descarga de proxy para los tipos de archivos que desea a través de WordPress. Supongamos que va a restringir el acceso a los archivos ".doc".

1. Defina una variable de consulta que indique el archivo solicitado

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

2. Actualice .htaccess para reenviar solicitudes de archivos restringidos a WordPress

Esto capturará solicitudes a los archivos que desea restringir y los enviará de vuelta a WordPress usando la variable de consulta personalizada anterior. Inserte la siguiente regla antes de las líneas RewriteCond .

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

3. Capture el nombre del archivo solicitado en la variable de consulta personalizada; y verifica el acceso al archivo:

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 ¡Esta solución funciona para instalaciones de un solo sitio solo ! Esto se debe a que WordPress MU ya reenvía las solicitudes de archivos cargados en los sub-sitios a través de wp-includes/ms-files.php . También hay una solución para WordPress MU, pero es un poco más complicado.

    
respondido por el Bendoh 12.09.2012 - 03:03
3

Recientemente tuve un problema relacionado y escribí este artículo al respecto .

Supondré que las descargas se cargan a través del manejo de medios de WordPress o, de lo contrario, tendrá un ID de archivo adjunto para la descarga.

Esquema de la solución

  • Haga que el directorio de cargas sea 'seguro' (en este sentido, solo significa usar .htaccess para bloquear cualquier intento de acceso directo a los archivos en el directorio de cargas (o un subdirectorio del mismo), por ejemplo, a través de mysite.com/wp-content/uploads/conf/2012/09/myconfidentialfile.pdf )
  • Cree un enlace de descarga que incluya el ID del archivo adjunto: esto pasa por WordPress para verificar que el permiso del usuario para ver el archivo adjunto permite / niega el acceso.

Advertencias

  • Esto hace uso de .htaccess para proporcionar seguridad . Si esto no está disponible / activado (servidores nginx por ejemplo), entonces no obtendrá mucha seguridad. Puede evitar que el usuario navegue por el directorio de uplods. Pero el acceso directo funcionará.
  • Según lo anterior. Esto no debe usarse en la distribución si necesita seguridad absoluta . Está bien si su configuración específica funciona, pero en general, no se puede garantizar. Mi artículo vinculado en parte está tratando de abordar esto.
  • Perderás miniaturas . El bloqueo del acceso directo a una carpeta o subcarpeta significará que no se pueden ver las miniaturas de los archivos en esa carpeta. Mi artículo vinculado está intentando en parte tratar esto.

Bloqueo de acceso directo

Para hacer esto en su carpeta de subidas (o en una subcarpeta, todo el material confidencial debe residir, a cualquier profundidad, dentro de esta carpeta). Coloque un archivo .htaccess con lo siguiente:

Order Deny,Allow
Deny from all

A continuación, asumo que adjuntará material confidencial para publicar el tipo "cliente". Cualquier medio cargado en la página de edición del cliente se almacenará en la carpeta uploads/conf/

La función para configurar el directorio de subidas protegidas

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

Subiendo material confidencial

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

    }

Una vez hecho esto, el contenido cargado debe estar dentro de uploads/conf y tratar de acceder a él directamente desde tu navegador no debería funcionar.

Descarga de contenido

Esto es fácil. La url de descarga puede ser algo www.site.com?wpse26342download=5 (donde 5 es el ID de adjunto del contenido cargado). Usamos esto para identificar el archivo adjunto, verificar los permisos del usuario actual y permitir que se descarguen.

Primero, configura la variable de consulta

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

Ahora configure un escucha para (tal vez) activar la descarga ...

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

Comentarios finales

El código anterior puede contener errores / errores de sintaxis y no se ha probado, y lo usa bajo su propio riesgo :).

El url de descarga puede ser "prettified" usando reescrituras. Como se indica en los comentarios, puede agregar un index.php en blanco dentro de cada elemento secundario de la carpeta protegida para evitar la exploración, pero esto debería evitarse con las reglas .htaccess de todos modos.

Un método más seguro sería almacenar los archivos públicos fuera de un directorio público. O en un servicio externo como Amazon S3. Para esto último, deberá generar una URL válida para recuperar el archivo de Amazon (usando su clave privada). Ambos requieren un cierto nivel de confianza en su servicio de Host / tercero.

Desconfiaba del uso de complementos que sugieran que ofrecen "descargas protegidas". No he encontrado ninguno que ofrezca suficiente seguridad. Por favor, no las advertencias de esta solución también, y agradecería cualquier sugerencia o crítica.

    
respondido por el Stephen Harris 27.09.2012 - 13:23
1

Probablemente, quizás hayas sabido este truco. Este código verificará el nombre de usuario actual del usuario que inició sesión y si coincide, mostrará un enlace de descarga a ese archivo, de lo contrario no mostrará nada.

aquí está el código:

<?php 
    global $current_user;
    get_currentuserinfo();

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

Sin embargo, esto no será un buen enfoque, ya que los archivos se almacenan en servidores, cualquier persona con un enlace puede descargar ese archivo.

    
respondido por el amit 09.07.2012 - 03:28
0

Supongo que esta información es confidencial y, por lo tanto, además de ocultar los enlaces a los archivos, querrá hacerlos completamente inaccesibles para cualquier persona en la web, incluso si adivinaran la URL, a menos que el usuario tenga explícitamente permiso para descargar los archivos.

Busque el almacenamiento de los archivos en Amazon S3 de forma segura y luego proporcione pre firmado (tiempo limitado) URL del archivo siempre que se hayan cumplido los controles de seguridad correctos (es decir, el usuario ha iniciado sesión en su sitio y es quien dice ser) ).

Hay un muy buen AWS SDK que hace que sea muy sencillo hacer esto.

Lo que necesitarás investigar es cómo enviar archivos cargados a través de la interfaz de carga de WP en S3, alternativamente, crea tu propia uploader .

Otra opción también sería buscar en el código de WP e-commerce . Ofrecen la descarga segura de archivos de software (por ejemplo, MP3). Creo que los archivos se convierten en hashes con una clave de cifrado que se genera por usuario en la compra. Esto tomaría un poco de desciframiento para ver cómo funcionaba, pero el proceso no será exclusivo de este complemento, por lo que habrá otros ejemplos disponibles (en algún lugar).

    
respondido por el deadlyhifi 27.08.2012 - 13:37
0

Creo que el cifrado de los archivos es el camino a seguir como la respuesta anterior. Hay un complemento en Wordpress.org que te permite proteger las descargas. enlace Usted podría utilizar el servicio de Amazon o Google Drive también. Hay muchos servicios que ofrecen descargas protegidas, como el buzón también.

    
respondido por el Chris 29.08.2012 - 22:06

Lea otras preguntas en las etiquetas