Como restringir o download de anexos a um usuário específico?

12

Eu tenho um caso de uso muito específico em que o site criado para um advogado e cada um de seus clientes pode acessar sua própria 'página / portal específicos' (tipo de postagem personalizada) sem a capacidade de acessar o wp-admin etc. criou todas as páginas de login / registro / edição de perfil no front end). Nesta página / portal o advogado deixará mensagens e arquivos para o cliente fazer o download , agora teoricamente falando, um cliente pode adivinhar (ou se tem conhecimento dos arquivos de outro cliente) outros nomes de arquivos e fazer o download criando um problema com privacidade / segurança / material confidencial, etc.

Estou procurando idéias / conceitos para uma solução, meu pensamento inicial era ter o link de download apontado para alguns download.php enviando o ID do anexo, o ID do usuário, o id da página / portal e nonce e o outro lado processando isso ..

o que você acha? estou no caminho certo ou essa abordagem é falha?

Obrigado!

    
por Amit 19.08.2011 / 16:22

5 respostas

5

O que precisa acontecer é que você precisa fazer o proxy das solicitações de download para os tipos de arquivo que você quer através do WordPress. Vamos supor que você esteja restringindo o acesso a arquivos ".doc".

1. Definir uma variável de consulta que indica o arquivo solicitado

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

2. Atualize o .htaccess para encaminhar solicitações de arquivos restritos para o WordPress

Isto irá capturar pedidos para os arquivos que você deseja restringir e enviá-los de volta ao WordPress usando a variável de consulta personalizada acima. Insira a seguinte regra antes das linhas RewriteCond .

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

3. Capture o nome do arquivo solicitado na variável de consulta personalizada; e verifique o acesso ao arquivo:

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 solução funciona apenas para instalações de sites únicos ! Isso ocorre porque o WordPress MU já encaminha solicitações de arquivos carregados em subsites por meio de wp-includes/ms-files.php . Existe uma solução para o WordPress MU também, mas é um pouco mais envolvente.

    
por Bendoh 12.09.2012 / 03:03
3

Recentemente tive um problema relacionado e escrevi este artigo sobre ele .

Assumirei que os downloads são enviados por meio do manuseio de mídia do WordPress - ou, caso contrário, você tem um ID de anexo para o download.

Esboço da solução

  • Tornar o diretório de uploads 'seguro' (nesse sentido, apenas significa usar .htaccess para bloquear qualquer tentativa de acessar diretamente os arquivos no diretório de uploads (ou um subdiretório deles) - por exemplo via mysite.com/wp-content/uploads/conf/2012/09/myconfidentialfile.pdf )
  • Crie um link para download incluindo o ID do anexo - isso passa pelo WordPress para verificar se a permissão do usuário para visualizar o anexo permite / nega acesso.

Advertências

  • Isso faz uso de .htaccess para fornecer segurança . Se isso não estiver disponível / ativado (servidores nginx, por exemplo), você não terá muita segurança. Você pode evitar que o usuário navegue no diretório uplods. Mas o acesso direto funcionará.
  • conforme acima. Isso não deve ser usado na distribuição se você precisar de segurança absoluta . Tudo bem se a sua configuração específica funcionar - mas, em geral, não pode ser garantida. Meu artigo vinculado está, em parte, tentando abordar isso.
  • Você perderá miniaturas . Bloquear o acesso direto a uma pasta ou subpasta significa que as miniaturas dos arquivos nessa pasta não podem ser visualizadas. Meu artigo vinculado está, em parte, tentando abordar isso.

Bloqueio de acesso direto

Para fazer isso na sua pasta de uploads (ou em uma subpasta, todo material confidencial deve residir, em qualquer profundidade, dentro dessa pasta). Coloque um arquivo .htaccess com o seguinte:

Order Deny,Allow
Deny from all

A seguir, suponho que você esteja anexando material confidencial para postar o tipo 'cliente'. Qualquer mídia carregada na página de edição do cliente será armazenada na pasta uploads/conf/

A função para configurar o diretório de uploads protegido

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

Upload de 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' );
                }
        }

    }

Feito isso, o conteúdo carregado deve estar dentro de uploads/conf e tentar acessá-lo diretamente usando seu navegador não deve funcionar.

Download de conteúdo

Isso é fácil. O URL de download pode ser algo em www.site.com?wpse26342download=5 (onde 5 é o ID do anexo do conteúdo enviado). Usamos isso para identificar o anexo, verificar as permissões do usuário atual e permitir o download.

Primeiro, configure a variável 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;
}}

Agora, configure um ouvinte para (talvez) acionar o 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;
}

Comentários finais

O código acima pode conter erros de bugs / sintaxe e não foi testado, e você o usa por sua conta e risco :).

O URL de download pode ser 'embelezado' usando reescrevê-lo. Conforme declarado nos comentários, você pode adicionar um index.php em branco dentro de cada filho da pasta protegida para impedir a navegação - mas isso deve ser impedido pelas regras .htaccess de qualquer maneira.

Um método mais seguro seria armazenar os arquivos públicos fora de um diretório público. Ou em um serviço externo como o Amazon S3. Para este último, você precisará gerar um URL válido para buscar o arquivo da Amazon (usando sua chave privada). Ambos exigem um certo nível de confiança em seu host / serviço de terceiros.

Eu ficaria preocupado em usar plug-ins que sugiram oferecer "downloads protegidos". Eu não encontrei nenhum que fornecesse segurança suficiente. Por favor, não as advertências desta solução também - e eu gostaria de receber sugestões ou críticas.

    
por Stephen Harris 27.09.2012 / 13:23
1

Provavelmente, você deve ter conhecido esse truque, Esse código verificará o nome de usuário atual do usuário conectado e, se ele corresponder, ele mostrará o link para download desse arquivo, caso contrário, ele não mostrará nada.

aqui está o código:

<?php 
    global $current_user;
    get_currentuserinfo();

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

No entanto, isso não será uma boa abordagem, já que os arquivos são armazenados em servidores, qualquer pessoa com link pode baixar esse arquivo.

    
por amit 09.07.2012 / 03:28
0

Suponho que essa informação é confidencial e, portanto, além de ocultar os links para os arquivos, você realmente os tornará inacessíveis completamente a qualquer pessoa na Web, mesmo se eles adivinharem o URL, a menos que esse usuário tenha explícito permissão para baixar os arquivos.

Procure armazenar os arquivos em Amazon S3 de forma segura e, em seguida, fornecendo URLs pré-assinados (com limite de tempo) para o arquivo, desde que as verificações de segurança corretas tenham sido satisfeitas (ou seja, o usuário tenha efetuado login em seu site e seja quem ele disser ).

Existe um AWS SDK muito bom que faz com que seja muito fácil fazer isso.

O que você precisará pesquisar é como enviar arquivos carregados através da interface de upload do WP para o S3, ou então construir seus próprios carregador .

Outra opção seria examinar o código do WP e-commerce . Eles oferecem download seguro de arquivos de software (por exemplo, MP3s). Eu acredito que os arquivos são convertidos em hashes com uma chave de criptografia que é gerada por usuário na compra. Isso levaria um pouco de decifração para ver como funcionava, mas o processo não será exclusivo deste plugin, então outros exemplos estarão disponíveis (em algum lugar).

    
por deadlyhifi 27.08.2012 / 13:37
0

Acho que a criptografia dos arquivos é o caminho a seguir como a resposta acima. Existe um plugin no Wordpress.org que permite proteger os downloads. enlace Você poderia usar o serviço amazons ou o Google Drive também. Existem muitos serviços que oferecem downloads protegidos, como drop box.

    
por Chris 29.08.2012 / 22:06