Cum să protejezi fișierele încărcate dacă utilizatorul nu este autentificat?

22 dec. 2011, 18:46:18
Vizualizări: 88.3K
Voturi: 107

Folosesc WordPress pentru un site privat unde utilizatorii încarcă fișiere. Folosesc "Private WordPress" pentru a preveni accesul în site dacă utilizatorul nu este autentificat.

Aș dori să fac același lucru pentru fișierele încărcate în directorul uploads.

Astfel, dacă un utilizator nu este autentificat, nu va putea accesa: https://xxxxxxx.com/wp-content/uploads/2011/12/xxxxxxx.pdf dacă încearcă să acceseze dar nu sunt autentificați, ar trebui să fie redirecționați către pagina de autentificare, de exemplu.

Am găsit un plugin numit private files, dar ultima actualizare a fost în 2009 și nu pare să funcționeze pe WordPress-ul meu.

Știe cineva vreo metodă? Ar fi suficientă o metodă de protecție împotriva hotlinking-ului pentru a proteja acest lucru?

Am găsit și această metodă:

# 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

Dar atunci orice utilizator care replică cookie-ul ar putea trece de această protecție, nu? Cu stimă

3
Comentarii

Există vreun motiv pentru care nu poți folosi un alt director de încărcare, cum ar fi unul în afara rădăcinii site-ului?

onetrickpony onetrickpony
22 dec. 2011 19:11:33

Nu chiar, dar deja am o mulțime de fișiere atașate postărilor în acel director. Nu mă deranjează să le mut pe toate dacă pot găsi o soluție adecvată.

chifliiiii chifliiiii
22 dec. 2011 19:37:52

În cazul în care redirecționezi automat utilizatorii către ecranul de autentificare, o modalitate ușoară de a proteja încărcările este să verifici referentul. Dacă referentul este gol (acces direct) sau diferit de domeniul pe care găzduiești fișierele, atunci îl blochezi.

Konstantinos Konstantinos
31 ian. 2020 19:55:38
Toate răspunsurile la întrebare 4
11
113

Doar verificarea existenței cookie-ului nu este o protecție foarte strictă.

Pentru o protecție mai puternică, puteți direcționa sau "proxi" toate cererile către folderul de încărcare (exemplu uploads în exemplul următor) printr-un script php:

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

Toate cererile către fișierele încărcate (care includ și imaginile din articole) vor fi direcționate către dl-file.php, care apoi poate verifica dacă utilizatorul este autentificat sau nu.

Dacă utilizatorul nu este autentificat, va fi afișat formularul de login al site-ului. După autentificare, utilizatorul va fi redirecționat înapoi către fișier și îl va putea descărca.

Exemplu dl-file.php.

Ceva similar poate fi găsit în \wp-includes\ms-files.php din instalarea WordPress, dar acel fișier este pentru multisite și fără verificarea de login și redirecționări.

În funcție de traficul site-ului dvs., ar putea fi indicat să integrați această soluție direct cu serverul, folosind de exemplu anteturile X-Accel-Redirect sau X-Sendfile.

2 ian. 2012 23:50:59
Comentarii

cum ajustez dl-file.php dacă vreau să stochez fișiere într-un subdirector precum wp-content/uploads/secure ?

User User
12 ian. 2012 00:54:57

Aceasta este singura soluție cu adevărat sigură. Orice altceva pe care îl puteți găsi pe web, cum ar fi verificarea header-ului referer, verificarea cookie-urilor, interzicerea listării directorului, reprezintă o măsură pe jumătate deoarece puteți falsifica cu ușurință headerele cererilor HTTP pentru a o ocoli.

Lukasz Lukasz
20 sept. 2013 11:58:28

Băieți... aceasta părea soluția perfectă pentru mine....problema este că folosesc PDFJS de la Mozilla pentru a accesa unele PDF-uri din folderul de upload, iar PDFJS utilizează headere de tip partial-content pentru a obține doar paginile care îl interesează...așa că această soluție nu funcționează pentru mine.

aveți sugestii??

Otto Nascarella Otto Nascarella
28 nov. 2014 19:24:06

@OttoNascarella: Cererile de conținut parțial către PHP au fost rezolvate începând de astăzi, aceasta este independentă de această întrebare WordPress. De fapt, întrebarea este deja destul de veche: Descărcări reluabile atunci când folosiți PHP pentru a trimite fișierul?

hakre hakre
5 dec. 2014 12:17:49

@hakre Dar despre unele dintre acele imagini folosite pe pagina principală a site-ului și orice utilizator care vizitează site-ul?

Îmi dă eroare 404 dacă nu sunt autentificat.

Dhaval Panchal Dhaval Panchal
1 mai 2018 11:30:58

Poate cineva să explice această linie de cod list($basedir) = array_values(array_intersect_key(wp_upload_dir(), array('basedir' => 1)))+array(NULL); și cum diferă de $basedir = wp_upload_dir()['basedir']

Tomas Eklund Tomas Eklund
2 apr. 2020 14:02:30

@TomasEklund: Cel mai probabil varianta ta este mai puțin complicată. Motivul pentru varianta originală este cel mai probabil compatibilitatea cu versiunile anterioare de PHP.

hakre hakre
4 apr. 2020 17:08:42

Minunat. Poate cineva să transforme această soluție într-un plugin WordPress?

Jian Chen Jian Chen
17 mai 2020 07:17:34

Notă laterală: funcționează în WordPress 5.6.

long long
4 mar. 2021 15:17:33

În configurarea mea Multisite, am avut probleme cu completarea locației fișierului cu codul furnizat. Această variantă a funcționat mai bine: $file = rtrim( DIR, '/' ) . $_SERVER['REQUEST_URI'];

Talha Imam Talha Imam
29 iul. 2021 22:40:29

Pentru nginx în fișierul de configurare al site-ului, în blocul server{}, am putut adăuga următoarele pentru a-l face să funcționeze: location /wp-content/uploads/ { rewrite ^/wp-content/uploads/(.*)$ /dl-file.php?file=$1 last; }

hax2024 hax2024
12 apr. 2022 00:23:31
Arată celelalte 6 comentarii
4
21

Două metode, simplă în 2. cu ajutorul unei reguli Apache sau în 1. cu ajutorul unui cod personalizat într-un plugin.

1. Plugin

Puteți scrie un plugin folosind hook-ul init și valoarea GET $_GET[ 'file' ];. Dacă utilizatorul are această valoare GET, săriți într-o funcție pentru a verifica drepturile de acces la fișiere: De exemplu, cu o casetă de bifare într-o Meta Box.

add_action( 'init', 'fb_init' );
function fb_init() {
    // aceasta într-o funcție pentru hook-ul init
    if ( '' != $_GET[ 'file' ] ) {
        fb_get_file( $_GET[ 'file' ] );
    }
}

funcția fb_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; Fișierul nu a fost găsit.' );
    }
    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 ) { // atașament găsit și părinte disponibil
            if ( post_password_required( $image[0] -> post_parent ) ) { // parola pentru postare nu este disponibilă
                wp_die( get_the_password_form() );// afișează formularul de parolă 
            }
            $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 {
            // nu este un atașament normal, verifică pentru 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' ] ) {// calea curentă a thumbnail-ului
                            foreach ( $meta[ 'sizes' ] as $SINGLEsize ) {
                                if ( $filename[ 'filename' ] . '.' . $filename[ 'extension' ] == $SINGLEsize[ 'file' ] ) {
                                    if ( post_password_required( $SINGLEimage -> post_parent ) ) { // parola pentru postare nu este disponibilă
                                        wp_die( get_the_password_form() );// afișează formularul de parolă 
                                    }
                                    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 ); // trimite întotdeauna acest lucru
    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' );

    // Suport pentru 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'] );
    // Dacă șirul este gol, returnează 0. Dacă nu, încearcă să-l analizezi într-un timestamp
    $client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0;

    // Creează un timestamp pentru cea mai recentă modificare...
    $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;
    }

    // Dacă am ajuns până aici, doar servește fișierul
    readfile( $file );
    die();
}

Puteți adăuga și un URL personalizat pentru fișiere prin hook-ul 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;
}

2. Verificare Apache pentru Cookie

Lăsați un nou fișier .htaccess în interiorul directorului /wp-content/uploads/. Sau un alt director definit pentru încărcări.

Cum funcționează

În interiorul containerelor <IfModule>, există trei reguli care fac următoarele:

  1. Verifică dacă cererea este pentru orice fișier
  2. Verifică absența unui cookie care începe cu wordpress_logged_in_
  3. Dacă aceste condiții sunt îndeplinite, cererea de fișier va fi respinsă prin răspunsul 403 "Forbidden"

Trucul aici este pasul 2, verificarea absenței unui cookie care începe cu wordpress_logged_in_. Când utilizatorul este autentificat, WordPress adaugă un cookie în browserul tău care arată astfel:

wordpress_logged_in_1234567890abcdefghijklmnopqrstuvwxyz

Exemplu de regulă cu verificare pentru tipul de fișier

# necesită autentificare pentru fișiere media
<IfModule mod_rewrite.c>
    RewriteCond %{REQUEST_FILENAME} (.*)
    RewriteCond %{HTTP_COOKIE} !wordpress_logged_in_([a-zA-Z0-9_]*) [NC]
    RewriteRule .* - [F,L]
</IfModule>
3 ian. 2012 12:20:25
Comentarii

Aceasta nu a funcționat la mine, știe cineva de ce? Am copiat exact.

Ryan S Ryan S
17 feb. 2014 12:40:26

Protecția funcționează doar pentru PDF. Alte extensii de fișiere nu funcționează, cum ar fi: doc, docx, jpg și altele...

Patel Patel
23 aug. 2017 13:43:48

Opțiunea 2 a funcționat perfect pentru toate tipurile de fișiere, mulțumesc.

crdunst crdunst
5 mar. 2021 18:23:21

De ce este condiția pentru dimensiunea fișierelor pentru IIS?

Scribblemacher Scribblemacher
11 mar. 2025 13:34:09
1

Dacă doriți o abordare bazată pe plugin pentru a rezolva această problemă, iată o soluție destul de bună pe care am găsit-o (în final):

  1. Instalați pluginul 'Download Monitor', disponibil la:
    https://wordpress.org/plugins/download-monitor/
  2. În Panoul de administrare WordPress, accesați noul element de meniu 'Descărcări' și adăugați o nouă 'Descărcare', conform instrucțiunilor de pe site-ul de documentație al pluginului aici: https://www.download-monitor.com/kb/adding-downloads/. Țineți cont de shortcode-ul 'Descărcare' furnizat (de ex., salvați-l în Notepad). Rețineți că fișierul este salvat în /wp-content/uploads/dlm_uploads/
  3. În căsuța metabox 'Opțiuni descărcare', specificați 'Doar pentru membri' (conform documentației de aici https://www.download-monitor.com/kb/download-options/), și faceți clic pe 'Publicare'.
  4. Pe pagina unde doriți să apară descărcarea pentru membri, adăugați shortcode-ul notat la pasul #2 și 'Publicați/Actualizați' pagina, conform documentației de aici: https://www.download-monitor.com/kb/shortcode-download/. Puteți modifica șablonul link-ului de descărcare conform acestui ghid https://www.download-monitor.com/kb/content-templates/, sau puteți crea unul propriu (de ex., pentru a elimina 'numărul de descărcări')
  5. Accesați pagina, ar trebui să vedeți un link de descărcare (dar care nu dezvăluie URL-ul fișierului). Dacă accesați aceeași pagină într-o fereastră nouă de browser (sau în mod Incognito), ar trebui să constatați că descărcarea nu mai funcționează.

Aceasta înseamnă că oricine nu este autentificat nu poate descărca fișierul sau vedea adresa reală a acestuia. În cazul în care cineva neautorizat descoperă URL-ul fișierului, pluginul blochează accesul la dosarul /wp-content/uploads/dlm_uploads/, împiedicând accesul direct la fișier.

Bonus: dacă faceți acest lucru pentru un site unde aveți nevoie ca utilizatorii să se autentifice doar ca 'Membri' (fără permisiuni WordPress precum editarea de pagini sau drepturi de Admin), instalați pluginul 'Members' https://wordpress.org/plugins/members/, creați un nou rol de utilizator numit 'Membru', și acordați-i singura capabilitate 'read', creați un nou utilizator în WordPress și atribuiți-i rolul 'Membru'.

Dacă doriți să protejați conținutul paginilor, pluginul 'Members' oferă câteva opțiuni, sau există alte pluginuri disponibile. Dacă doriți să personalizați pagina de autentificare pentru membri, astfel încât să arate mai bine decât formularul implicit WordPress, folosiți un plugin precum 'Theme My Login': https://wordpress.org/plugins/theme-my-login/

13 apr. 2017 12:09:36
Comentarii

Procesul pe care l-am descris mai sus este explicat și aici, deși după cum puteți vedea, nu trebuie să fie specific doar pentru fișierele PDF: http://www.thedigitalcrowd.com/website-development/wordpress/wordpress-restrict-access-to-pdf-downloads-with-private-members-login-details/

Matty J Matty J
13 apr. 2017 12:11:01
0

Cum ar fi o abordare bazată pe plugin-uri pentru rezolvarea acestei probleme, am găsit un plugin WP creat special pentru această situație:

Prevenirea accesului la fișiere/directoare: https://wordpress.org/plugins/prevent-file-access/

8 ian. 2021 16:28:32