phpMyAdmin Security Hack - kompletten pma Ordner sperren
Dieser Artikel beschreibt, wie man den kompletten phpMyAdmin Ordner vor Zugriff schützen kann, ohne eine zweite Passwort Abfrage via .htacces einbauen zu müssen. Verwendet wird dabei die http Authentifizierungsmethode von phpMyAdmin selbst.
Dabei wird phpMyAdmin so angepasst, dass beim Login ein Cookie gesetzt wird. Dieses Cookie mann man via .htacces Abfragen. Falls nun dieses Cookie nicht existiert, oder den falschen Wert enthält, kann man via mod_rewrite alle Anfragen auf eine Fehlerseite umleiten.
So sind alle Dateien im phpMyAdmin Ordner vor Anfragen von nicht angemeldeten Usern geschützt.
Apache Konfiguration
In der vHost Konfiguration vom Apache müssen die AllowOverride Optionen FileInfo und AuthConfig aktiviert sein, damit mod_rewrite und http Authentifikation funktioniert.
phpMyAdmin Konfiguration
In phpMyAdmin sollte die Authentifikationsmethode auf http gestellt werden. Man ändert dabei einfach den Wert der Variable auth_type auf http.
| 1 2 3 | $cfg['Servers'][$i]['auth_type'] = 'http'; |
Cookie Hash
Nun müssen wir und noch einen Wert für das Cookie überlegen. Ich verwende dabei einen 45 Zeichen langen Zufallsstring aus Zahlen, Kein- und Großbuchstaben.
Ein simpler Weg sich sowas Generieren zu lassen, ist ein Passwortgenerator.
| 1 2 | Beispiel:
MqYuh0m1nkBfTkyDqmDhBXA2RRIGDeTKOXYXlfLUc9l4a |
.htaccess
In der .htaccess Datei, die im Hauptverzeichnis von phpMyAdmin angelegt werden muss, werden zuerst die Dateien für die Fehlerausgabe definiert. Mit der Direktive ErrorDocument kann man für jeden http Status Code eine Datei festlegen.
400 (Unauthorized), 403 (Forbidden) und 404 (Not Found) sind dabei die wichtigsten.
Liegt phpMyAdmin in einem Unterordner der Domain, muss der Pfad angepasst werden. Beispielweise in /phpMyAdmin/error.html, wenn die Addresse zu phpMyAdmin http://www.example.com/phpMyAdmin ist.
Mit mod_rewrite wird dann noch überprüft, ob es das Cookie gibt, sowie ob es den richtigen Wert enthält. Trifft dies nicht zu, werden alle Anfragen die nicht auf error.html oder index.php gehen auf error.html umgeleitet.
Die Flags hinter der Rewrite Rule ([R=403,L]) bedeuten dabei, dass ein Redirect mit dem Status Code 403 gemacht wird, und das nach dieser Regel keine weitere geparst werden soll.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # Error Dokument festlegen
ErrorDocument 401 /error.html
ErrorDocument 403 /error.html
ErrorDocument 404 /error.html
RewriteEngine on
RewriteBase /
# Cookie Checken | Cookie Hash |
RewriteCond %{HTTP_COOKIE} !login-status=MqYuh0m1nkBfTkyDqmDhBXA2RRIGDeTKOXYXlfLUc9l4a [NC]
RewriteCond %{REQUEST_URI} !^/error.html$ [NC]
RewriteCond %{REQUEST_URI} !^/index.php$ [NC]
RewriteCond %{REQUEST_URI} !^/$ [NC]
RewriteRule ^(.*)$ /error.html [R=403,L] |
Möchte man außer error.html und index.php noch mehr Dateien erlauben, kann man einfach eine weitere RewriteCond hinzufügen.
Cookie anlegen
Um das Cookie anlegen zu können, fügen wir einfach eine Zeile in die index.php hinzu.
In dem Codeblock ist ein Ausschnitt aus der Datei zu sehen, damit man die Stelle besser findet, wo die Zeile hin muss. Die Zeile selbst ist mit einem Kommentar davor und einem Kommentar dahinter markiert.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | $url_query = PMA_generate_common_url($_GET); if (isset($GLOBALS['target']) && is_string($GLOBALS['target']) && !empty($GLOBALS['target']) && in_array($GLOBALS['target'], $goto_whitelist)) { $main_target = $GLOBALS['target']; } $main_target .= $url_query; $lang_iso_code = $GLOBALS['available_languages'][$GLOBALS['lang']][2]; // start output header('Content-Type: text/html; charset=' . $GLOBALS['charset']); #--> NEUE ZEILE ---------------------------------------------------------------------------- setcookie("login-status", "4MbeBAkNHc1d3PXCT4rg8rQHWP7rZ8Uv16ofyVywTP6t6", time()+99999999); #--> NEUE ZEILE ENDE ----------------------------------------------------------------------- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang=" echo $lang_iso_code; " lang=" echo $lang_iso_code; " dir=" echo $GLOBALS['text_dir']; "> <head> |
Cookie entfernen
Um das Cookie beim Logout wieder zu löschen, fügen wir eine Ähnliche Zeile in der Datei libraries/auth/http.auth.lib.php hinzu.
In dem Codeblock ist wieder ein Ausschnitt aus der Datei zu sehen, damit man die Stelle besser findet, wo die Zeile hin muss. Die Zeile selbst ist auch hier wieder mit einem Kommentar davor und einem Kommentar dahinter markiert.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | function PMA_auth() { /* Perform logout to custom URL */ if (!empty($_REQUEST['old_usr']) && !empty($GLOBALS['cfg']['Server']['LogoutURL'])) { PMA_sendHeaderLocation($GLOBALS['cfg']['Server']['LogoutURL']); exit; } if (empty($GLOBALS['cfg']['Server']['verbose'])) { $server_message = $GLOBALS['cfg']['Server']['host']; } else { $server_message = $GLOBALS['cfg']['Server']['verbose']; } // remove non US-ASCII to respect RFC2616 $server_message = preg_replace('/[^\x20-\x7e]/i', '', $server_message); #--> NEUE ZEILE ----------------------------------------------------------------------- setcookie("login-status", "", time()-1); #--> NEUE ZEILE ENDE ------------------------------------------------------------------ header('WWW-Authenticate: Basic realm="phpMyAdmin ' . $server_message . '"'); header('HTTP/1.0 401 Unauthorized'); if (php_sapi_name() !== 'cgi-fcgi') { header('status: 401 Unauthorized'); } // Defines the charset to be used header('Content-Type: text/html; charset=' . $GLOBALS['charset']); /* HTML header */ $page_title = $GLOBALS['strAccessDenied']; require './libraries/header_meta_style.inc.php'; |
error.html
Die error.html wird im Hauptverzeichnis von phpMyAdmin angelegt.
Was dort nun letzendlich drin steht, ist dem Benutzer überlassen. Man könnte dort zum Beispiel eine php Datei anlegen, und dann jeden Fehlversuch mitloggen. Oder halt einfach nur eine Fehlermeldung ausgeben.




