php-Sicherheit: Wie sicher ist die vBulletin gettemplate-Funktion?

Cordula

Grünschnabel
Hallo liebe Helfer auf tutorials.de,

ich habe vor längerem einmal eine Applikation mit einer Templatefunktion programmiert, die größtenteils auf der in diesem Tutorial (http://www.tutorials.de/php-tutorials/12907-php-templates.html) beschriebenen vBulletin Templatefunktion basierte.

Momentan befasse ich mich eingehender mit dem Thema php-Sicherheit und überprüfe in diesem Zuge natürlich insbesondere auch älteren Code.

Abgesehen davon, dass die Lösung der obigen Funktion mit eval(); mir etwas umständlich zu sein scheint, habe ich nun häufiger gelesen, dass aus Sicherheitsgründen auf die Verwendung von eval() am Besten völlig zu verzichten sei, da sonst im schlimmsten Fall User ausführbaren (php-)Code einschleusen könnten.

Nun habe ich zuhause ein wenig herumprobiert und für den Fall
PHP:
eval($_GET['userinput']);

sowie für
PHP:
eval("?>texttext<?".$_GET['userinput']."?> texttext")

das Problem reproduzieren können, jedoch nicht für den Fall

PHP:
eval ("\$str .= \"".gettemplate("wiederholung")."\";");

oder

PHP:
eval ("dooutput(\"".gettemplate("Layout")."\");");

Nun bin ich in solchen Dingen auch nicht sonderlich begabt, deshalb wollte ich mir hier genauere Beurteilung einholen, da ich mir nicht sicher bin, ob es jetzt tatsächlich erst einmal keinen Weg zum Einschleusen gibt, oder ich ihn nur nicht gefunden habe.

Meine Erklärung für das unterschiedliche Verhalten der Verwendung von eval() ist aktuell wiefolgt: Während in den ersten beiden Beispielen der zu evaluierende String direkt vom User bestimmt werden kann, wird in den anderen beiden Beispielen der zu evaluierende String aus einer Datei gelesen, die der User nicht beeinflussen kann. Den einzigen Einfluss den der User nehmen kann ist auf den Inhalt der "Platzhalter" die in der Html-Datei üblicherweise (weil Templatesystem) enthalten sind, diese werden aber erst durch eval() gefüllt und nicht von eval() erneut ausgeführt (das wird nur die Templatedatei).

Zwei Sicherheitsverbesserungen (bzw. eine Verbesserung und eine Offensichtlichkeit :) )habe ich mir an dieser Stelle dann überlegt:

1) natürlich sollte jeder Wert, den eval() in den Platzhalter einsetzt validiert werden, das könnte passieren durch striptags() htmlentities(), regexps, sowie einen blacklistcheck. Habt ihr dafür noch zusätzliche Anregnungen?

2) der in gettemplate eingelesen Code könnte in Anlehnung an diese Funktion
(von php.net http://php.net/manual/de/function.eval.php) zumindest auf Funktionsnamen
getestet und z.B. per str_replace() escaped werden (der volle Test ruiniert mAn den HTML-Code). Wie seht ihr das, ist das überhaupt nützlich?

PHP:
<?php 
function safe_eval($code,&$status) { //status 0=failed,1=all clear 
    //Signs 
        //Can't assign stuff 
    $bl_signs = array("="); 

    //Language constructs 
    $bl_constructs = array("print","echo","require","include","if","else", 
"while","for","switch","exit","break");    

    //Functions 
    $funcs = get_defined_functions(); 
    $funcs = array_merge($funcs['internal'],$funcs['user']); 

    //Functions allowed        
        //Math cant be evil, can it? 
    $whitelist = array("pow","exp","abs","sin","cos","tan"); 
    
    //Remove whitelist elements 
    foreach($whitelist as $f) { 
        unset($funcs[array_search($f,$funcs)]);    
    } 
    //Append '(' to prevent confusion (e.g. array() and array_fill()) 
    foreach($funcs as $key => $val) { 
        $funcs[$key] = $val."("; 
    } 
    $blacklist = array_merge($bl_signs,$bl_constructs,$funcs); 
    
    //Check 
    $status=1; 
    foreach($blacklist as $nono) { 
        if(strpos($code,$nono) !== false) { 
            $status = 0; 
            return 0; 
        } 
    } 

    //Eval 
    return @eval($code); 
} 
?>

Vielen Dank für's Durchlesen und für eure Hilfe!

Cordula
 
Zurück