Como proteger uploads, se o usuário não estiver logado?

80

Eu uso o wordpress para um site privado onde os usuários enviam arquivos. Eu uso o "WordPress Privado" para impedir o acesso ao site se o usuário não estiver logado.

Gostaria de fazer o mesmo com os arquivos enviados na pasta de uploads.

Portanto, se um usuário não estiver logado, ele não poderá acessar: https://xxxxxxx.com/wp-content/uploads/2011/12/xxxxxxx.pdf se tentar acessar, mas não estiver logado, deverá ser redirecionado para a página de login, por exemplo.

Eu encontrei um plugin chamado arquivos privados, mas a última vez que atualizei foi em 2009 e ele parece não funcionar no meu wordpress.

Alguém conhece algum método? O método hotlinking será suficiente para proteger isso?

Eu também encontrei este método:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^.*uploads/private/.*
RewriteCond %{HTTP_COOKIE} !^.*wordpress_logged_in.*$ [NC]
RewriteRule . /index.php [R,L]
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

Mas qualquer usuário que replique o cookie pode passar isso certo? Saudações

chifliiiii
fonte
1
Alguma razão para você não poder usar um diretório de upload diferente, como um fora da raiz do site?
Onetrickpony
Não realmente, mas eu já tenho toneladas de arquivos anexados a mensagens nesse diretório, eu não mente em movimento ao redor se eu posso encontrar uma solução adequada
chifliiiii

Respostas:

86

Verificar apenas se o cookie existe não é uma proteção rigorosa.

Para obter uma proteção mais forte, você pode passar ou "proxy" todas as solicitações para a pasta carregada (exemplo uploadsno exemplo a seguir) por meio de um script php:

RewriteCond %{REQUEST_FILENAME} -s
RewriteRule ^wp-content/uploads/(.*)$ dl-file.php?file=$1 [QSA,L]

Todas as solicitações para arquivos enviados (que incluem imagens em postagens) iriam para as dl-file.phpquais, então, é possível verificar se o usuário está logado ou não.

Se o usuário não estiver logado, o formulário de login do seu site será mostrado. Depois que o usuário estiver conectado, ele será redirecionado novamente para o arquivo e poderá fazer o download agora.

Exemplardl-file.php .

Algo semelhante pode ser encontrado na \wp-includes\ms-files.phpsua instalação do wordpress, mas essa é para multisite e sem a verificação e redirecionamento de login.

Dependendo da quantidade de tráfego que você possui, pode ser melhor integrá-lo ao seu servidor, por exemplo, X-Accel-Redirectou X-Sendfilecabeçalhos.

hakre
fonte
1
como você ajusta dl-file.php se eu quiser armazenar arquivos em um subdiretório como wp-content / uploads / secure?
Esta é a única solução realmente segura. Qualquer outra coisa que você possa encontrar na web, como verificar o cabeçalho do referenciador, verificar cookies, proibir a listagem de diretórios, é uma meia medida, já que você pode facilmente falsificar cabeçalhos de solicitações HTTP para contorná-lo.
Lucas
Pessoal .. esta parecia a solução perfeita para mim .... o problema é que estou usando o PDFJS da Mozilla para acessar alguns PDFs da pasta de upload, e o PDFJS usa cabeçalhos de conteúdo parcial para obter apenas as páginas nas quais está interessado. .para esta solução não é fácil para mim. alguma sugestão??
Otto Nascarella 28/11
@OttoNascarella: As solicitações de conteúdo parcial para o PHP foram resolvidas a partir de hoje, isso é independente dessa pergunta do wordpress. De fato, a pergunta já é bastante antiga: downloads recuperáveis ​​ao usar o PHP para enviar o arquivo?
hakre
@hakre Que tal algumas dessas imagens usadas na primeira página do site e qualquer usuário que vem visitar o site? Dá-me um erro 404 se não estiver logado.
Dhaval Panchal
14

Você também pode escrever um plug-in usando o initgancho e o valor-get $_GET[ 'file' ];. Se o usuário tiver esse valor, pule para uma função para verificar os direitos de acesso aos arquivos: Por exemplo, com uma caixa de seleção em uma Meta Box.

add_action( 'init', 'fb_init' );
function fb_init() {
    // this in a function for init-hook
    if ( '' != $_GET[ 'file' ] ) {
        fb_get_file( $_GET[ 'file' ] );
    }
}

a função get_file ()

function fb_get_file( $file ) {

    $upload     = wp_upload_dir();
    $the_file   = $file; 
    $file       = $upload[ 'basedir' ] . '/' . $file;
    if ( !is_file( $file ) ) {
        status_header( 404 );
        die( '404 &#8212; File not found.' );
    }
    else {
        $image = get_posts( array( 'post_type' => 'attachment', 'meta_query' => array( array( 'key' => '_wp_attached_file', 'value' => $the_file ) ) ) );
        if ( 0 < count( $image ) && 0 < $image[0] -> post_parent ) { // attachment found and parent available
            if ( post_password_required( $image[0] -> post_parent ) ) { // password for the post is not available
                wp_die( get_the_password_form() );// show the password form 
            }
            $status = get_post_meta( $image[0] -> post_parent, '_inpsyde_protect_content', true );

            if ( 1 == $status &&  !is_user_logged_in() ) {
                wp_redirect( wp_login_url( $upload[ 'baseurl' ] . '/' . $the_file ) );
                die();
            }
        }
        else {
            // not a normal attachment check for thumbnail
            $filename   = pathinfo( $the_file );
            $images     = get_posts( array( 'post_type' => 'attachment', 'meta_query' => array( array( 'key' => '_wp_attachment_metadata', 'compare' => 'LIKE', 'value' => $filename[ 'filename' ] . '.' . $filename[ 'extension' ] ) ) ) );
            if ( 0 < count( $images ) ) {
                foreach ( $images as $SINGLEimage ) {
                    $meta = wp_get_attachment_metadata( $SINGLEimage -> ID );
                    if ( 0 < count( $meta[ 'sizes' ] ) ) {
                        $filepath   = pathinfo( $meta[ 'file' ] );
                        if ( $filepath[ 'dirname' ] == $filename[ 'dirname' ] ) {// current path of the thumbnail
                            foreach ( $meta[ 'sizes' ] as $SINGLEsize ) {
                                if ( $filename[ 'filename' ] . '.' . $filename[ 'extension' ] == $SINGLEsize[ 'file' ] ) {
                                    if ( post_password_required( $SINGLEimage -> post_parent ) ) { // password for the post is not available
                                        wp_die( get_the_password_form() );// show the password form 
                                    }
                                    die('dD');
                                    $status = get_post_meta( $SINGLEimage -> post_parent, '_inpsyde_protect_content', true );

                                    if ( 1 == $status &&  !is_user_logged_in() ) {
                                        wp_redirect( wp_login_url( $upload[ 'baseurl' ] . '/' . $the_file ) );
                                        die();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    $mime       = wp_check_filetype( $file );

    if( false === $mime[ 'type' ] && function_exists( 'mime_content_type' ) )
        $mime[ 'type' ] = mime_content_type( $file );

    if( $mime[ 'type' ] )
        $mimetype = $mime[ 'type' ];
    else
        $mimetype = 'image/' . substr( $file, strrpos( $file, '.' ) + 1 );

    header( 'Content-type: ' . $mimetype ); // always send this
    if ( false === strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS' ) )
        header( 'Content-Length: ' . filesize( $file ) );

    $last_modified = gmdate( 'D, d M Y H:i:s', filemtime( $file ) );
    $etag = '"' . md5( $last_modified ) . '"';
    header( "Last-Modified: $last_modified GMT" );
    header( 'ETag: ' . $etag );
    header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + 100000000 ) . ' GMT' );

    // Support for Conditional GET
    $client_etag = isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ? stripslashes( $_SERVER['HTTP_IF_NONE_MATCH'] ) : false;

    if( ! isset( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) )
        $_SERVER['HTTP_IF_MODIFIED_SINCE'] = false;

    $client_last_modified = trim( $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
    // If string is empty, return 0. If not, attempt to parse into a timestamp
    $client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0;

    // Make a timestamp for our most recent modification...
    $modified_timestamp = strtotime($last_modified);

    if ( ( $client_last_modified && $client_etag )
        ? ( ( $client_modified_timestamp >= $modified_timestamp) && ( $client_etag == $etag ) )
        : ( ( $client_modified_timestamp >= $modified_timestamp) || ( $client_etag == $etag ) )
        ) {
        status_header( 304 );
        exit;
    }

    // If we made it this far, just serve the file
    readfile( $file );
    die();
}

Você também pode adicionar um URL personalizado para arquivos através do gancho generate_rewrite_rules

add_filter( 'generate_rewrite_rules', 'fb_generate_rewrite_rules' );

function fb_generate_rewrite_rules( $wprewrite ) {
        $upload = wp_upload_dir();
        $path = str_replace( site_url( '/' ), '', $upload[ 'baseurl' ] );
        $wprewrite -> non_wp_rules = array( $path . '/(.*)' => 'index.php?file=$1' );
        return $wprewrite;
}
bueltge
fonte
Isso não funcionou do meu lado, alguém sabe por quê? Eu copio exatamente.
Ryan S
Proteção funcionando apenas em pdf. outra extensão arquivos não funcionando como: doc, docx, jpg e etc ...
Patel
1

Se você deseja uma abordagem baseada em plug-in para resolver esse problema, aqui está uma solução razoavelmente boa que eu encontrei (finalmente):

  1. Instale o plug-in 'Download Monitor', disponível em:
    https://wordpress.org/plugins/download-monitor/
  2. No Painel do WordPress, vá para o novo item de menu 'Downloads' e adicione um novo 'Download', conforme descrito no site de documentação do plugin aqui: https://www.download-monitor.com/kb/adding-downloads/ . Anote o código de acesso 'Download' fornecido para você (por exemplo, salve no Bloco de notas). Observe que o arquivo é salvo em/wp-content/uploads/dlm_uploads/
  3. Na metabox 'Opções de download', especifique 'Somente membros' (conforme documentado aqui https://www.download-monitor.com/kb/download-options/ ) e clique em 'Publicar'.
  4. Na página em que você deseja que o download apenas dos Membros apareça, adicione o código de acesso que você anotou na etapa 2 e 'Publique / Atualize' a página, conforme documentado aqui: https://www.download-monitor.com / kb / shortcode-download / . Você pode alterar o modelo do link de download conforme descrito aqui https://www.download-monitor.com/kb/content-templates/ ou criar o seu próprio (por exemplo, para remover a 'contagem' do download)
  5. Navegue até sua página, você verá um link de download (mas que não revela o URL do arquivo de download). Se você navegar para a mesma página em uma nova janela do navegador (ou janela anônima), deverá descobrir que o download não funciona mais.

Isso significa que qualquer pessoa que não esteja logada não pode baixar o arquivo ou ver a URL real do arquivo. Se alguém não autorizado descobrir o URL do arquivo, o plug-in também interromperá a navegação do usuário no URL real do arquivo, bloqueando o acesso à /wp-content/uploads/dlm_uploads/pasta.

Bônus: se você estiver fazendo isso em um site em que precisa que os usuários possam fazer login apenas como 'Membros' (mas não possuam permissões do WordPress, como edição de páginas ou administrador), instale o plugin 'Membros' https: // wordpress .org / plugins / members / , crie uma nova função de usuário chamada 'Membro' e ofereça a capacidade única de 'ler', crie um novo usuário no WordPress e certifique-se de atribuir a eles a função de 'Membro'.

Se você deseja proteger o conteúdo das páginas, o plug-in 'Membros' fornece algumas opções ou existem outros plug-ins por aí. Se você deseja colocar um tema na página de login para que os Membros tenham uma aparência melhor do que o formulário de login padrão do WordPress, use algo como 'Tema meu login': https://wordpress.org/plugins/theme-my-login/

Matty J
fonte
O processo que eu descrevi acima é também explicado aqui, embora, como você pode ver que não tem que ser específico para apenas PDFs: thedigitalcrowd.com/website-development/wordpress/...
Matty J