Cum să protejezi fișierele încărcate dacă utilizatorul nu este autentificat?
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ă

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

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

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.

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??

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

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']

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

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

Î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'];

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 — 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:
- Verifică dacă cererea este pentru orice fișier
- Verifică absența unui cookie care începe cu
wordpress_logged_in_
- 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>

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

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

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):
- Instalați pluginul 'Download Monitor', disponibil la:
https://wordpress.org/plugins/download-monitor/ - Î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/
- Î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'.
- 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')
- 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/

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/

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/
