Beveiliging Code snippets

Encrypted file upload en download in WordPress

Een bestand wordt in WordPress standaard geupload in de media library, en zijn vrij toegankelijk, zolang je het url maar hebt. Als je gebruikers bestanden willen uploaden met gevoelige informatie, moet het downloaden geblokkeerd worden. Om te voorkomen dat de inhoud op straat ligt bij een hack, is het verstandig ook de inhoud te versleutelen  met encryptie. Tot slot kan de bestandsnaam informatie bevatten. Deze vervangen we door een willekeurig gegenereerde titel.

In dit artikel ga ik ervan uit dat het je zelf lukt om bestanden te uploaden, met de standaard html, of wat gelikter met bijvoorbeeld dropzone.js.

De functie om te encrypten is vrij eenvoudig:

Eerst hebben we een functie nodig om de key en iv te genereren. De input hiervan kan je op vele manieren maken. Belangrijk is natuurlijk dat je altijd dezelfde wachtwoorden gebruikt voor encrypten en decrypten. Het beveiligen hiervan verdient wel de aandacht natuurlijk. Als deze te makkelijk te achterhalen zijn is de encryptie waardeloos. Je zou bijvoorbeeld bij elke gebruiker een aparte key kunnen opslaan voor zijn bestanden.

function dtc_get_passphrase(){
 $secret_iv = "Een geheim wachtwoord voor de iv";
 $secret_key = "Een geheim wachtwoord voor de key";
 $iv = substr(hash('sha256', $secret_iv),0,32);
 $key = substr(hash('sha256', $secret_pass),0,32);
 $opts = array('iv'=>$iv, 'key'=>$key);
 return $opts;

}

/* in: path to file */

public function encrypt($file){

$opts = dtc_get_passphrase();

$content = file_get_contents($file);
 $fp = fopen($file, 'wb');
 $content = rtrim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $opts["key"], $content, MCRYPT_MODE_CBC, $opts["iv"])), "\0\3");

fwrite($fp, $content);
 fclose($fp);
 }

Om te voorkomen dat de bestanden gedownload kunnen worden blokkeren we dit met de .htaccess. In de folder waar de bestanden komen, en die volledig geblokkeerd moet worden, maak je een htaccess bestand aan met de volgende inhoud:

<FilesMatch ".*">
 Order Allow,Deny
 Deny from All
 </FilesMatch>

Om het bestand te decrypten en dan te downloaden zonder het via een url aan te roepen moet je een link maken naar een bestand, bijvoorbeeld download.php. In dat bestand komt deze code, die ook WordPress inlaadt. Dit kan je bijvoorbeeld aanroepen met domein.nl/download.php?attachment_id=1

<?php
 # No need for the template engine
 define( 'WP_USE_THEMES', false );

#find the base path
 define( 'BASE_PATH', find_wordpress_base_path()."/" );

# Load WordPress Core
 require_once( BASE_PATH.'wp-load.php' );
 require_once( BASE_PATH.'wp-includes/class-phpass.php' );
 require_once( BASE_PATH . 'wp-admin/includes/image.php' );

if (is_user_logged_in() && isset($_GET["attachment_id"]) && is_numeric($_GET["attachment_id"])){

$attachment_id = intval($_GET["attachment_id"]);

$file =get_attached_file($attachment_id); //deze functie haalt het bestand uit de WordPress media library. Als je die niet gebruikt, moet je deze functie natuurlijk ook aanpassen.
 if (!$file) return "Niets gevonden.";
 $opts = dtc_get_passphrase();

$fp = fopen($file, 'rb');
 $content = file_get_contents($file);

if ($fp) {
 $fsize = filesize($file);
 $path_parts = pathinfo($file);
 $ext = strtolower($path_parts["extension"]);
 switch ($ext) {
 case "pdf":
 header("Content-type: application/pdf");
 break;
 case "zip":
 header("Content-type: application/zip");
 break;
 default:
 header("Content-type: application/octet-stream");
 break;
 }
 header("Content-Disposition: attachment; filename=\"".$path_parts["basename"]."\"");
 header("Content-length: $fsize");
 header("Cache-control: private"); //use this to open files directly
 $content = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $opts["key"], base64_decode($content), MCRYPT_MODE_CBC, $opts["iv"]), "\0\3");

echo $content;
 }
 else {
 echo "Er is iets fout gegaan.";
 }
 fclose($fp);
 }
 if(!function_exists('_log')){
 function _log( $message ) {
 if( WP_DEBUG === true ){
 if( is_array( $message ) || is_object( $message ) ){
 error_log( print_r( $message, true ) );
 } else {
 error_log( $message );
 }
 }
 }
 }

function find_wordpress_base_path() {
 $dir = dirname(__FILE__);
 do {
 //it is possible to check for other files here
 if( file_exists($dir."/wp-config.php") ) {
 return $dir;
 }
 } while( $dir = realpath("$dir/..") );
 return null;
 }

 

 

 

Related Articles

  • Berichten en pagina’s uitsluiten van het de WordPress zoekfunctie

    De WordPress zoekfunctie is heel handig, maar je wilt niet altijd alle pagina’s erin laten terugkomen. Met een simpele functie die je aan je functions.php toevoegd kan je dit regelen....
  • vorige volgende post bij een custom post type

    In de single.php, page.php of singular.php van een custom post type kreeg ik het niet voor elkaar om een simpele “vorige”, “volgende” post link toe te voegen. de previous_post_link() van...
  • Een enkele sticky post tonen

    Sticky posts zijn handig als je bijvoorbeeld op je homepage één post wilt tonen die blijft “plakken”, dus niet alleen de meest recente, maar een post of artikel die daar...
  • Google Analytics spamvrij maken en houden

    Last van referral spam? Door de stappen in dit artikel te volgen lees je weer betrouwbare gegevens af van Google Analytics. Toekomstige referral spam voorkomen Dit zouden standaardinstellingen voor ieder...

Laat een reactie achter