Lo scenario è quello che riguarda un’installazione WordPress esposta su Internet ma che tiene al riparo da occhi indiscreti i suoi contenuti permettendone la visione solo a coloro che sono registrati (le registrazioni sono chiuse e vengono controllate da chi gestisce il sito web). Come si fa a proteggere la cartella che sappiamo essere liberamente accessibile per chi ha un URL completo che punta a un suo contenuto?
Proteggere la cartella wp-content
La soluzione in realtà è abbastanza vecchia ma funziona ancora. Si parte da una pagina PHP che si occuperà di processare tutte le richieste di download dalla cartella , questo comprende chiaramente immagini e altro materiale (come elementi del tema) che non viene certamente scaricato dall’utente, ma dal browser che in quel momento intende navigare nel sito web in questione. Il codice sorgente della pagina PHP (che dovrà risiedere nella cartella principale del tuo WordPress, quella che contiene anche per capirci) è ancora disponibile su Gist. Te lo propongo anche qui di seguito:
<?php /* * dl-file.php * * Protect uploaded files with login. * * @link http://wordpress.stackexchange.com/questions/37144/protect-wordpress-uploads-if-user-is-not-logged-in * * @author hakre <http://hakre.wordpress.com/> * @license GPL-3.0+ * @registry SPDX */ require_once('wp-load.php'); is_user_logged_in() || auth_redirect(); list($basedir) = array_values(array_intersect_key(wp_upload_dir(), array('basedir' => 1)))+array(NULL); $file = rtrim($basedir,'/').'/'.str_replace('..', '', isset($_GET[ 'file' ])?$_GET[ 'file' ]:''); if (!$basedir || !is_file($file)) { status_header(404); die('404 — File not found.'); } $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 );
Il resto del lavoro lo farà il tuo file che forzerà la mano al browser costringendolo a passare per questo file PHP per poter ottenere ogni file da caricare nella pagina, che si tratti di elementi del tema o PDF che la persona intende scaricare:
RewriteCond %{REQUEST_FILENAME} -s RewriteRule ^wp-content/uploads/(.*)$ dl-file.php?file=$1 [QSA,L]
Pulisci eventuali cache e database, applica le modifiche e porta tutto in produzione, prova ad accedere qualsiasi file contenuto in , WordPress dovrebbe costringere il tuo browser a spostarsi sulla pagina di autenticazione dove dovrai farti riconoscere prima di poter mettere mano al contenuto che hai richiesto. Se invece eri già autenticato su WordPress dovresti riuscire ad arrivare al file richiesto come nulla fosse mai cambiato.
Buon lavoro!
L'articolo potrebbe non essere aggiornato
Questo post è stato scritto più di 5 mesi fa, potrebbe non essere aggiornato. Per qualsiasi dubbio ti invito a lasciare un commento per chiedere ulteriori informazioni! :-)