RSA Verschlüsselung unter PHP

Vor kurzem habe ich einige Präsentationen über Sicherheit in PHP-Anwendungen gesehen. Ein Thema dabei war, dass die gute alte MD5-Verschlüsselung bei Passwörtern nicht mehr ganz so sicher ist, weil es inzwischen einige einfache Methoden zur „Entschlüsselung“ gibt (z.B. mit Rainbow Tables oder Hash-Datenbanken). Ein erster Lösungsansatz zur Verbesserung der Passwortverschlüsselung ist häufig ein „Salt“ an den MD5-Hash anzuhängen, um es dem Angreifer zumindest zu erschweren. Aus meiner Sicht ist das allerdings mehr ein Workaround als eine wirklich sichere Lösung, daher habe ich nach einer Alternative zu MD5 gesucht und bin bei der RSA-Verschlüsselung hängengeblieben. Da es etwas kniffelig ist, die RSA-Verschlüsselung in einer PHP-Anwendung zu implementieren, gibt es von mir hier ein kleines HowTo. Ihr könnt die Verschlüsselung natürlich nicht nur für Passwörter verwenden, sondern für alle möglichen Daten.

Wie immer beginnen wir mit den Voraussetzungen:

  • Apache mit OpenSSL zur Schlüssel-Generierung
    (Am einfachsten ist XAMPP)
  • PHP mit OpenSSL-Extension
  • Zend_Crypt-Komponente aus dem Zend Framework

Bevor wir irgendetwas verschlüsseln können, benötigen wir aber zunächst ein Schlüsselpaar. Dieses Schlüsselpaar lässt sich relativ einfach mittels OpenSSL generieren. OpenSSL wird in den meisten Fällen bei einer Apache-Installation mitgeliefert (bei einer aktuellen XAMPP-Version ist es in jedem Fall dabei).
Ich habe das Schlüsselpar unter Windows generiert, ihr könnt es natürlich auch unter Linux oder Mac machen, es könnte aber sein, dass einige Befehle dann etwas abweichen.

Wir öffnen also Kommandozeile unter Windows (Start > Ausführen > „cmd“ eingeben; für alle, die das nicht sooft machen). Anschließend springen wir in das Verzeichnis, wo die Datei openssl.exe liegt:

cd C:\xampp\apache\bin

Das ist der Standard bei XAMPP.

Jetzt wird der öffentliche Schlüssel generiert. Dazu wird folgender Befehl benötigt:

openssl genrsa -des3 -out pub.key 1024

Das Programm fragt nach einem Passwort, das wir uns neu ausdenken müssen. Am besten man nimmt irgendeine kryptische Zeichenreihenfolge. Ihr könnt euch das Passwort auch aufschreiben, das ist aber nicht unbedingt notwendig.

Wenn ihr jetzt in das Verzeichnis von OpenSSL schaut, müsste dort eine neue Datei „pub.key“ liegen. Diese brauchen wir jetzt, um aus dem eingegeben öffentlichen Schlüssel einen privaten Schlüssel zu generieren. Der private Schlüssel wird dazu benötigt, um später die verschlüsselten Daten wieder entschlüsseln zu können. Der folgende Befehl erstellt die Datei mit dem privaten Schlüssel:

openssl rsa -in pub.key -out private.key

Ihr werdet nochmal nach dem zuvor angegebenen Passwort gefragt und schon wurde die Datei „private.key“ mit dem privaten Schlüssel erstellt.

Jetzt generieren wir noch das eigentliche Zertifikat, das wir zum Verschlüsseln der Daten benötigen:

openssl req -new -key private.key -x509 -out rsa.crt -days 3650 -config "C:\xampp\apache\bin\openssl.cnf"

Bevor OpenSSL die Zertifikatsdatei „rsa.crt“ erstellt, werden noch einige Werte wie das Land, Ort, Name und E-Mail Adresse abgefragt.
Achtung: Wichtig ist, dass der Pfad zur Konfigurationsdatei von OpenSSL korrekt ist. Der hier angegebene Pfad ist zumindest unter XAMPP der Standard.

So, das Zertifikat ist erstellt und wir legen die Dateien „rsa.crt“ und „private.key“ in ein Verzeichnis ab, auf das PHP Zugriff hat, aber von Außen nicht erreicht kann. Wer RSA ausschließlich zum Verschlüsseln von Daten verwenden möchte, kann die Datei mit dem privaten Schlüssel „private.key“ auch erstmal weglassen.

Kommen wir nun zur Programmierung – die Dank der Zend Framework Komponente Zend_Crypt_Rsa nur aus wenigen Codezeilen besteht. Ich habe zur Verschlüsselung eine kleine statische Klasse geschrieben:

class RsaEncryption
{
	protected static $_rsa = null;
 
	/**
	 * Returns Zend_Crypt_Rsa object.
	 *
	 * @return Zend_Crypt_Rsa
	 */
	public static function getRsa()
	{
		if(self::$_rsa === null)
		{
			self::$_rsa = new Zend_Crypt_Rsa(array(
				'certificatePath' => '/pfad/zum/zertifikat/rsa.crt',
				'pemPath' => '/pfad/zum/privatekey/private.key', // Diese Zeile auskommentieren, falls Entschlüsselung nicht benötigt wird
			));
		}
		return self::$_rsa;
	}
 
	public static function encryptData($data, $format = Zend_Crypt_Rsa::BASE64)
	{
		$rsa = self::getRsa();
		return $rsa->encrypt($data, $rsa->getPublicKey(), $format);
	}
 
	public static function decryptData($data, $format = Zend_Crypt_Rsa::BASE64)
	{
		$rsa = self::getRsa();
		return $rsa->decrypt($data, $rsa->getPrivateKey(), $format);
	}
}

So, jetzt lassen sich Daten mit der neuen Klassen ganz einfach ver- und wieder entschlüsseln. Hier ein kleines Beispiel:

$klartext = "Basti-sama's Blog";
$encrypted = RsaEncryption::encryptData($klartext);
$decrypted = RsaEncryption::decryptData($encrypted);
echo "Klartext: $encrypted<br/>";
echo "Verschlüsselt: $encrypted<br/>";
echo "Entschlüsselt: $decrypted";

Wundert euch bitte nicht über das Base64-Format. Das bedeutet nicht, dass die Daten nur mit Base64 verschlüsselt sind, sondern dies dient lediglich dazu, um die Ausgabe lesbar zu formatieren. Wenn man das $format auf null ändert, werden die verschlüsselten Daten direkt als Binär zurückgegeben und das sieht bei der Ausgabe dann doch etwas komisch aus.

Fehlt nur noch das Schlusswort (vielleicht könnt ihr euch ja schon denken was jetzt kommt).
Obwohl diese Verschlüsselungsmethode für Passwörter deutlich sicherer ist als ein einfacher MD5-Hash, lässt sie sich trotzdem irgendwie knacken, auch wenn es für den Angreifer einiges an Aufwand bedeutet.

Ein Kommentar zu “RSA Verschlüsselung unter PHP

  1. Gute Anleitung, ich schreib mal noch eine WICHTIGE Ergänzung.

    Anstatt 1024 hier: openssl genrsa -des3 -out pass.key 1024, empfehle ich 2048, besser 4096…durch zunehmendes cloud computing zu empfehlen.

    Zend_Crypt installieren, für Ubuntu hier: http://wiki.ubuntuusers.de/Zend-Framework

    Wenn es bei euch einen open_basedir Fehler gibt, dann liegt das entweder an Plesk, oder daran, dass ihr eurer php.ini des Webservers die Verzeichnisse hinter dem Pfad httpdocs, oder htdocs nicht freigegeben habt.
    PHP muss auf Zend zugreifen können !
    Bestenfalls unter domain/conf/http.include folgendes ändern:
    Wenn ihr mehrere 2412412414_http.include Dateien habt in diesem Verzeichnis, dann nehmt die aktuellste.
    Das Wort domain müsst ihr natürlich ersetzen durch eure z.B. web-union.de

    php_admin_flag engine on
    php_admin_flag safe_mode 0
    # off (alte Einstellung)
    php_admin_value open_basedir none
    # /var/www/vhosts/domain/httpdocs/:/tmp/ (alte Einstellung)

    Falls Zend dann immernoch nicht funktionieren sollten. Müsst hier an dieser Stelle weiter forschen, checkt nochmal die Pfade ;-).
    Notfalls den Zend Ordner in httpdocs legen und den direkten Zugriff darauf sperren. Pfade wieder anpassen nicht vergessen und testen ob Zend funktioniert, siehe Zend Installationslink.

    Wenn das tut dann könnt ihr die PHP Datei oben verwenden, allerdings fehlt noch eine Zeile in dieser Datei, diese muss zuerst in der PHP Datei stehen:
    require_once(„pfad_zu_Zend/libzend-framework-php/Zend/Crypt/Rsa.php“);
    Ihr müsste „pfad_zu_Zend“ natürlich anpassen je nachdem wie eurer aussieht.

    Das sollte dem ein oder anderen der mit diesem tutorial Probleme hat etwas weiterhelfen und Zeit sparen ;-).

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.