Come proteggere i file caricati se l'utente non ha effettuato l'accesso?
Uso WordPress per un sito privato dove gli utenti caricano file. Utilizzo il plugin "Private WordPress" per impedire l'accesso al sito se l'utente non ha effettuato il login.
Vorrei fare lo stesso con i file caricati nella cartella uploads.
Quindi se un utente non ha effettuato l'accesso non dovrebbe poter accedere a: https://xxxxxxx.com/wp-content/uploads/2011/12/xxxxxxx.pdf se provano ad accedere ma non sono loggati dovrebbero essere reindirizzati alla pagina di login ad esempio.
Ho trovato un plugin chiamato private files ma l'ultimo aggiornamento risale al 2009 e non sembra funzionare sul mio WordPress.
Qualcuno conosce un metodo? Il metodo hotlinking sarà sufficiente per proteggere questo?
Ho trovato anche questo metodo:
# 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
Ma in questo caso qualsiasi utente che replica il cookie potrebbe bypassare questa protezione, giusto? Saluti

Verificare solo l'esistenza del cookie non costituisce una protezione particolarmente rigorosa.
Per ottenere una protezione più forte, puoi instradare o "proxare" tutte le richieste alla cartella degli upload (nell'esempio seguente uploads
) attraverso uno script PHP:
RewriteCond %{REQUEST_FILENAME} -s
RewriteRule ^wp-content/uploads/(.*)$ dl-file.php?file=$1 [QSA,L]
Tutte le richieste ai file caricati (comprese le immagini nei post) verranno indirizzate a dl-file.php
che potrà verificare se l'utente è loggato o meno.
Se l'utente non è loggato, verrà mostrato il form di login del sito. Dopo il login, l'utente verrà reindirizzato al file e potrà scaricarlo.
Qualcosa di simile si trova in \wp-includes\ms-files.php
nella tua installazione WordPress, ma è pensato per il multisito e senza il controllo del login e i reindirizzamenti.
A seconda del traffico che hai, potrebbe essere consigliabile integrare meglio questa soluzione con il tuo server, ad esempio utilizzando gli header X-Accel-Redirect
o X-Sendfile
.

come si modifica dl-file.php se voglio memorizzare i file in una sottocartella come wp-content/uploads/secure ?

Questa è l'unica soluzione veramente sicura. Tutto ciò che puoi trovare sul web, come controllare l'header referer, controllare i cookie, disabilitare la visualizzazione delle directory, è una mezza misura poiché è facile falsificare gli header delle richieste HTTP per aggirarla.

Ragazzi...questa sembrava la soluzione perfetta per me...il problema è che sto usando PDFJS di Mozilla per accedere ad alcuni PDF dalla cartella upload, e PDFJS utilizza header partial-content per ottenere solo le pagine che gli interessano...quindi questa soluzione non è praticabile per me.
qualche suggerimento??

@OttoNascarella: Le richieste di contenuto parziale a PHP sono state risolte a partire da oggi, questo è indipendente da questa domanda su WordPress. Infatti, la domanda è piuttosto vecchia: Download riprendibili quando si usa PHP per inviare il file?

@hakre E per alcune di quelle immagini usate nella homepage del sito quando un utente visita il sito?
Mi dà un errore 404 se non sono loggato.

Qualcuno potrebbe spiegare questa riga di codice list($basedir) = array_values(array_intersect_key(wp_upload_dir(), array('basedir' => 1)))+array(NULL);
e in cosa differisce da $basedir = wp_upload_dir()['basedir']

@TomasEklund: Il tuo è probabilmente meno complicato. Un motivo per quello originale è molto probabilmente la compatibilità con le versioni precedenti di PHP.

Fantastico. Qualcuno potrebbe per favore trasformare questa soluzione in un plugin per Wordpress?

Nella mia configurazione Multisite, ho avuto problemi a popolare la posizione del file con il codice fornito. Questa soluzione ha funzionato meglio: $file = rtrim( DIR, '/' ) . $_SERVER['REQUEST_URI'];

Due modi, semplice in 2. con l'aiuto di una regola apache o in 1. con l'aiuto di codice personalizzato in un plugin.
1. Plugin
Puoi scrivere un plugin utilizzando l'hook init
e il valore get $_GET[ 'file' ];
. Se l'utente ha questo valore get, salta in una funzione per controllare i diritti di accesso ai file: Ad esempio, con una checkbox all'interno di una Meta Box.
add_action( 'init', 'fb_init' );
function fb_init() {
// questo in una funzione per l'hook init
if ( '' != $_GET[ 'file' ] ) {
fb_get_file( $_GET[ 'file' ] );
}
}
la funzione 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 — File non trovato.' );
}
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 ) { // allegato trovato e genitore disponibile
if ( post_password_required( $image[0] -> post_parent ) ) { // password per il post non disponibile
wp_die( get_the_password_form() );// mostra il form della password
}
$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 {
// non un allegato normale, controlla per la miniatura
$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' ] ) {// percorso corrente della miniatura
foreach ( $meta[ 'sizes' ] as $SINGLEsize ) {
if ( $filename[ 'filename' ] . '.' . $filename[ 'extension' ] == $SINGLEsize[ 'file' ] ) {
if ( post_password_required( $SINGLEimage -> post_parent ) ) { // password per il post non disponibile
wp_die( get_the_password_form() );// mostra il form della password
}
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 ); // sempre invia questo
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' );
// Supporto per 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'] );
// Se la stringa è vuota, restituisce 0. Altrimenti, tenta di analizzarla in un timestamp
$client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0;
// Crea un timestamp per la nostra modifica più recente...
$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;
}
// Se siamo arrivati fin qui, serviamo semplicemente il file
readfile( $file );
die();
}
Puoi anche aggiungere un URL personalizzato per i file tramite l'hook 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. Controllo Apache per il Cookie
Lascia un nuovo file .htaccess all'interno della directory /wp-content/uploads/
. O un'altra directory definita per gli upload.
Come funziona
All'interno dei container <IfModule>
, ci sono tre regole che fanno quanto segue:
- Controlla se la richiesta è per qualsiasi file
- Controlla l'assenza di un cookie che inizia con
wordpress_logged_in_
- Se queste condizioni sono soddisfatte, la richiesta del file sarà negata tramite risposta 403 "Forbidden"
Il trucco qui è il passaggio 2, quindi controlla l'assenza di un cookie che inizia con wordpress_logged_in_
. Quando l'utente è loggato, WordPress aggiunge un cookie al tuo browser che assomiglia a:
wordpress_logged_in_1234567890abcdefghijklmnopqrstuvwxyz
Esempio di regola con un controllo per il tipo di file
# richiede il login per i file media
<IfModule mod_rewrite.c>
RewriteCond %{REQUEST_FILENAME} (.*)
RewriteCond %{HTTP_COOKIE} !wordpress_logged_in_([a-zA-Z0-9_]*) [NC]
RewriteRule .* - [F,L]
</IfModule>

Non ha funzionato nel mio caso, qualcuno sa perché? Ho copiato esattamente.

La protezione funziona solo per i PDF. Le altre estensioni di file non funzionano come: doc, docx, jpg ecc...

L'opzione 2 ha funzionato perfettamente per tutti i tipi di file, grazie.

Se preferisci un approccio basato su plugin per risolvere questo problema, ecco una soluzione ragionevolmente buona che ho (finalmente) trovato:
- Installa il plugin 'Download Monitor', disponibile su:
https://wordpress.org/plugins/download-monitor/ - Nella Dashboard di WordPress, vai alla nuova voce di menu 'Downloads' e aggiungi un nuovo 'Download', come descritto nella documentazione del plugin qui: https://www.download-monitor.com/kb/adding-downloads/.
Prendi nota dello shortcode 'Download' fornito (ad esempio salvalo in Notepad). Nota che il file viene salvato in
/wp-content/uploads/dlm_uploads/
- Nella metabox 'Download options', specifica 'Members only' (come documentato qui https://www.download-monitor.com/kb/download-options/), e clicca 'Publish'.
- Nella pagina in cui vuoi che appaia il download riservato ai membri, inserisci lo shortcode che hai annotato nel passaggio #2, e 'Pubblica/Aggiorna' la pagina, come documentato qui: https://www.download-monitor.com/kb/shortcode-download/. Puoi modificare il template del link di download come descritto qui https://www.download-monitor.com/kb/content-templates/, o crearne uno tuo (ad esempio per rimuovere il conteggio dei download)
- Naviga sulla tua pagina, dovresti vedere un link per il download (ma che non rivela l'URL del file). Se accedi alla stessa pagina in una nuova finestra del browser (o in modalità Incognito), dovresti scoprire che il download non funziona più.
Ciò significa che chiunque non sia loggato non può né scaricare il file né vedere il vero URL del file. Nel caso in cui qualcuno non autorizzato scoprisse l'URL del file, il plugin blocca anche l'accesso alla cartella /wp-content/uploads/dlm_uploads/
impedendo la navigazione diretta al file.
Bonus: se stai implementando questo per un sito in cui gli utenti devono poter accedere solo come 'Membri' (senza permessi WordPress come la modifica delle pagine o essere Admin), installa il plugin 'Members' https://wordpress.org/plugins/members/, crea un nuovo ruolo utente chiamato 'Member', e assegnagli solo la capacità 'read', crea un nuovo utente in WordPress, e assicurati di assegnargli il ruolo 'Member'.
Se vuoi proteggere il contenuto delle pagine, il plugin 'Members' offre alcune opzioni, oppure ci sono altri plugin disponibili. Se vuoi personalizzare la pagina di login per i Membri in modo che sia più accattivante del form di login predefinito di WordPress, usa qualcosa come 'Theme My Login': https://wordpress.org/plugins/theme-my-login/

Il processo che ho descritto sopra è spiegato anche qui, anche se come puoi vedere non deve essere specifico solo per i PDF: http://www.thedigitalcrowd.com/website-development/wordpress/wordpress-restrict-access-to-pdf-downloads-with-private-members-login-details/

Che ne dici di un approccio basato su plugin per risolvere questo problema? Ho trovato un plugin per WordPress creato proprio per questo:
Prevenire l'accesso a file/cartelle: https://wordpress.org/plugins/prevent-file-access/
