PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


TLS/SSL für Heimwerker

with 5 comments

Gastartikel von Oliver Sperke.

Ich bin 34 Jahre alt und seit 10 Jahren selbständiger Webentwickler. Mein Fokus liegt dabei auf der Erstellung, Beratung und Optimierung in den Bereichen High Performance, Usability und Sicherheit in den gängigsten Internetsprachen: PHP, HTML, Javascript und CSS.

In den vorhergehenden Beiträgen habe ich ja schon locker über Passwörter und wie man mit Ihnen umgehen sollte erzählt. Dabei wurde auch immer wieder mal angemerkt, dass meistens nicht der Login, sondern die Übertragung dieser Daten das eigentliche Problem wäre. „Man in the middle“, „Sniffer“ und der ganze … Mist. Das beste Mittel gegen viele Sicherheitsprobleme ist sicher SSL oder neu TLS, nur leider ist das für manche Webmaster immer noch nicht einsetzbar. Warum weiß ich persönlich nicht, denn eine zusätzliche IP, die evtl. benötigt wird, liegt bei etwa 1 Euro/Monat und einfache Shared Zertifikate, die meistens vollkommen ausreichen gibt es kostenlos.

Wer aus welchen Gründen auch immer kein TLS einsetzen kann oder will, sollte sich mit anderen Mitteln helfen. Das Ziel muss sein, alle wirklich sensiblen Daten (E-Mail, Passwörter, etc) so zu übertragen, dass sie auf dem Transport nicht gelesen werden können. Das ist schwierig, denn spätestens unser Server sollte es lesen können. Eine Idee ist, die Passwörter mit Einweghashes zu bearbeiten. Da unsere Passwörter aber natürlich sicher verstaut sind, können wir mit dem ankommendem Passwort nichts anfangen. Selbst wenn wir diesen Mechanismus in Javascript komplett nachbauen, wie kriegen wir den geheimen systemweiten Salt rein? Ausserdem gäben wir einem potentiellem „schlimmen Finger“ wichtige Informationen, was im Jahr 2011 keine gute Idee ist. Eine symmetrische Verschlüsselung kommt ebenfalls nicht in Frage, weil wir müssten mindestens einmal den Schlüssel übertragen, was das Verfahren überflüssig macht.

Die einzige sichere Möglichkeit ist das Verfahren, dass auch TLS benutzt. Asymmetrische Verschlüsselung! Da uns per Aufgabenstellung kein TLS zur Verfügung steht, ist unser Ziel, dieses Verfahren möglichst sicher zu kopieren – TLS für Heimwerker. Auch dieses Verfahren ist nicht ganz einfach, denn man muss zusätzliche Software installieren (können). Ich versuche den Aufwand und die Erklärungen aber so einfach wie möglich zu halten. Ein wirklicher Vorteil: Einmal eingerichtet ist es auf unbegrenzt viele Domains auf einem Server anwendbar, völlig unabhängig von der IP. Ein Anwendungszweck, der mir spontan einfällt sind Blog- oder Forenanbieter, wo die Anschaffung von Wildcardzertifikaten zu teuer wäre.


DEMO DOWNLOAD

Diese Anleitung ist sehr lang, aber keine Panik. Es sind sehr viele Ausgaben dabei. Auch wenig erfahrene Benutzer sollten alles hin bekommen. Ihr braucht etwa 30 Minuten Zeit und ein paar Grundkenntnisse auf der Linuxkonsole. Falls Euch „Programme installieren“ und „Textdateien bearbeiten“ nicht überfordern, könnt Ihr sofort loslegen. Trotzdem empfehle ich, den Text einmal ganz zu lesen und erst dann anzufangen und was immer Ihr kaputt macht, ist nicht eine Schuld!

Wie funktioniert TLS?

Zunächst einmal müssen wir das Prinzip von Öffentlichen und Privaten Schlüsseln verstehen. Da stellen ma uns ma janz dumm Das ganze System kann man sich vorstellen wie ein Briefkasten. Jeder, der die Adresse (also den öffentlichen Schlüssel/Publickey) kennt, kann etwas einwerfen, aber nur der Empfänger kann den Briefkasten mit seinem Briefkastenschlüssel (privater Schlüssel/Privatekey) öffnen und die Post lesen. Nach diesem Prinzip funktioniert z. B. das sichere Versenden von E-Mails seit Jahren. Jeder, der meinen öffentlichen Schlüssel kennt, kann mir „hübsche Kryptopäckchen“ packen, die aber nur ich auspacken kann.

Beim Verschlüsseln von Webseiten über TLS kommt noch eine weitere wichtige Komponente hinzu und das ist die digitale Signatur eines Schlüssels. Eine dritte unabhängige Stelle „signiert“ den öffentlichen Schlüssel und bestätigt damit „meine Adresse“. Auf mein Beispiel übertragen: Vor meinem Briefkasten ruft man als Besucher erst noch mal bei der Hotline an und fragt nach, ob die Adresse auch noch richtig ist oder ob der Inhaber den Schlüssel als Verloren gemeldet hat oder ob es andere Gründe gibt, dort nichts mehr einzuwerfen.

Um eine verschlüsselte Verbindung herzustellen sendet ein Besucher Informationen mit meinem (bestätigtem) Publickey zum Server, der antwortet und bestätigen damit zusätzlich, dass er es selbst sind. Der Browser des Besuchers kann jetzt einen zufälligen Schlüssel erzeugen und dem Webserver zusenden. Der Webserver bestätigt diesen Schlüssel (Handshake) und wir können dann sicher (symmetrisch) kommunizieren. Das ist zwar aufwendig, aber es bietet Sicherheit, ohne am eigentlichen Protokoll rum schrauben zu müssen.

Wie wir das nutzen können

In unserem Fall geht es nur darum, Informationen vom Besucher zum Webserver zu schicken. Ein Handshake und eine dauerhafte verschlüsselte Verbindung ist also nicht nötig (wenn auch möglich). Dementsprechend würde es in unserem Fall ausreichen, statt eines Handshakes direkt die Daten mit dem öffentlichem Schlüssel geschützt zum Webserver zu übertragen. Da nur der Webserver über den privaten Schlüssel verfügt, kann niemand, der die Verbindung belauscht mit den Informationen etwas anfangen.

Die Basisarbeiten

Um eine Verschlüsselung mit Schlüsselpaaren zu realisieren, wäre es natürlich sinnig, erst mal so ein Schlüsselpaar zu haben. Bei der Umsetzung habe ich mich hier für gnupg entschieden. Dieses Verfahren ist schon lange im Einsatz und nebenbei, wenn man seinen Webserver entsprechend eingerichtet hat, kann man auch problemlos verschlüsselte E-Mails senden und empfangen. Eine Möglichkeit, die ich bei aktuellen Webprojekten bisher leider sehr selten sehe.

Wir melden uns also zunächst einmal auf unserem Server an und zwar als der Benutzer, der auch die PHP Prozesse bearbeitet und in der gleichen Umgebung. Da ich Webserver und PHP gerne in einer chroot laufen habe, melde ich mich also am Server an und wechsele auf das Rootverzeichnis und den Benutzer. Wenn Ihr keine chroot habt und root den Apache steuert, dann meldet Ihr Euch einfach als root an und sagt es niemandem.

Ich gehe hier einfach mal von Debian/Ubuntu aus. Andere Betriebssysteme funktionieren ähnlich. Lediglich die Pfade und Programme könnten anders heißen.

chroot /var/jail
su webserver

Als nächstes benötigen wir gnupg, falls es noch nicht installiert ist.

sudo apt-get install gnupg

Danach erzeugen wir unser Schlüsselpaar und hangeln uns durch den Einstellungsassistenten.

$ gpg --gen-key

Ich habe hier RSA mit 4096 Bit gewählt, weil es die beste Sicherheit bietet. Der Name und die E-Mail spielen keine Rolle. Die Berechnung kann einige Sekunden bis Minuten dauern.

gpg (GnuPG) 1.4.10; Copyright (C) 2008 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Bitte wählen Sie, welche Art von Schlüssel Sie möchten:
   (1) RSA und RSA (voreingestellt)
   (2) DSA und Elgamal
   (3) DSA (nur unterschreiben/beglaubigen)
   (4) RSA (nur signieren/beglaubigen)
Ihre Auswahl? 1
RSA-Schlüssel können zwischen 1024 und 4096 Bit lang sein.
Welche Schlüssellänge wünschen Sie? (2048) 4096
Die verlangte Schlüssellänge beträgt 4096 Bit
Bitte wählen Sie, wie lange der Schlüssel gültig bleiben soll.
         0 = Schlüssel verfällt nie
        = Schlüssel verfällt nach n Tagen
      w = Schlüssel verfällt nach n Wochen
      m = Schlüssel verfällt nach n Monaten
      y = Schlüssel verfällt nach n Jahren
Wie lange bleibt der Schlüssel gültig? (0)
Schlüssel verfällt nie
Ist dies richtig? (j/N) j

Sie benötigen eine User-ID, um Ihren Schlüssel eindeutig zu machen; das
Programm baut diese User-ID aus Ihrem echten Namen, einem Kommentar und
Ihrer Email-Adresse in dieser Form auf:
    "Heinrich Heine (Der Dichter) "

Ihr Name ("Vorname Nachname"): MeinWebserver
Email-Adresse:
Kommentar:
Sie haben diese User-ID gewählt:
    "MeinWebserver"

Ändern: (N)ame, (K)ommentar, (E)-Mail oder (F)ertig/(B)eenden? f
Sie benötigen eine Passphrase, um den geheimen Schlüssel zu schützen.

Wir müssen eine ganze Menge Zufallswerte erzeugen.  Sie können dies
unterstützen, indem Sie z.B. in einem anderen Fenster/Konsole irgendetwas
tippen, die Maus verwenden oder irgendwelche anderen Programme benutzen.

gpg: Schlüssel 09C9929C ist als uneingeschränkt vertrauenswürdig gekennzeichnet
Öffentlichen und geheimen Schlüssel erzeugt und signiert.

gpg: "Trust-DB" wird überprüft
gpg: 3 marginal-needed, 1 complete-needed, PGP Vertrauensmodell
gpg: Tiefe: 0  gültig:   1  unterschrieben:   0  Vertrauen: 0-, 0q, 0n, 0m, 0f, 1u
pub   4096R/09C9929C 2011-07-19
  Schl.-Fingerabdruck = EB51 FBD8 E2A1 081D 40B9  4D74 448C C464 09C9 929C
uid                  MeinWebserver
sub   4096R/E606E242 2011-07-19

Für die weitere Bearbeitung sollten wir uns zwei Zeilen merken. In der ersten steht die KeyID des Schlüssels (09C9929C) und in der nächsten der Fingerabdruck. Die beiden Werte können wir in eine leere Textdatei kopieren (oder anders sichern), weil wir sie später noch brauchen.

pub   4096R/09C9929C 2011-07-19
Schl.-Fingerabdruck = EB51 FBD8 E2A1 081D 40B9  4D74 448C C464 09C9 929C

Als nächstes benötigen wir unseren öffentlichen Schlüssel, mit dem der Besucher später die Daten verschlüsseln kann.

$ gpg -a --export 09C9929C > key.pub

Es wird eine Datei erzeugt mit Inhalt, der diesem ähnlich sein sollte.

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.10 (GNU/Linux)

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
SJKoLAOV684mC+q9NwmGHqxncljH7r7Gbz/+sg==
=UM3f
-----END PGP PUBLIC KEY BLOCK-----

PHP spricht „gnupgäisch“

Unser Server kann jetzt gnupg, also wird es Zeit, das auch PHP beizubringen. Dafür gibt es eine spezielle Erweiterung, die uns qualvolle Hacks mit system() oder Schlimmeres (gibt es das?) erspart. Um diese Erweiterung zu installieren, müssen wir zunächst einmal PEAR und einige Basistools installieren. Danach installieren wir unsere PHP Erweiterung mit PEAR, das für uns das heruntergeladen, kompilieren und installieren übernimmt.

sudo apt-get install build-essentials gnupg php-pear
sudo pecl install gnupg

Im letzten Schritt müssen wir dann noch PHP selbst sagen, dass es da eine neue Erweiterung gibt. Dafür können wir entweder die php.ini selbst bearbeiten und die Zeile extension=gnupg.so hinzufügen oder entsprechende ini Dateien anlegen. Kopiert bitte nur die Befehle, die Ihr wirklich braucht. Ich habe jetzt einfach mal die üblichsten Möglichkeiten aufgeschrieben.

echo "extension=gnupg.so" > /etc/php5/cli/conf.d/gnupg.ini
echo "extension=gnupg.so" > /etc/php5/cgi/conf.d/gnupg.ini
echo "extension=gnupg.so" > /etc/php5/fpm/conf.d/gnupg.ini
echo "extension=gnupg.so" > /etc/php5/conf.d/gnupg.ini

Damit die Änderungen wirksam werden, müssen wir jetzt entweder den Apache/PHP-FPM neu starten oder alle PHP Prozesse beenden (z. B. mit dem Holzhammer killall). Mit php -m | grep gnupg könnt Ihr testen, ob das Modul geladen wurde.

Erster Funktionstest

Um zu testen, ob alles funktioniert legen wir zunächst eine Testdatei über die Konsole an und versuchen sie dann mit PHP zu entschlüsseln. Die KeyID müsst Ihr natürlich anpassen.

$ echo "Testnachricht" | gpg -a --encrypt -r 09C9929C > encrypted.gpg

Dann erzeugen wir eine neue Datei test.php z. B. mit

nano test.php

und füllen Sie mit diesem Inhalt. Ich habe hier mal die Zeilen kommentiert, das mache ich später nicht mehr ausführlich, um es übersichtlich zu halten.

<?php
	// gnupg initialisieren
	putenv("GNUPGHOME=/home/webserver/.gnupg");
	$res = gnupg_init();

	// Fingerabdruck ohne Leerzeichen und Passwort ändern!
	gnupg_adddecryptkey($res, "EB51FBD8E2A1081D40B94D74448CC46409C9929C", "DeinPasswort");

	// Nachricht entschlüsseln und ausgeben
	echo trim(gnupg_decrypt($res, file_get_contents('encrypted.gpg')));
?>

Ein Aufruf von php test.php sollte jetzt „Testnachricht“ ausgeben. Wenn Ihr hier angekommen seid, habt Ihr es im Prinzip geschafft, denn der Rest ist nur noch etwas HTML und Javascript.

php test.php

Unser Loginformular

Um Daten vom Besucher zum Webserver zu bringen benötigen wir ein einfaches Formular. Dieses kann so aussehen, kann aber natürlich auch andere Daten enthalten oder anderen Zwecken dienen (Anmeldung, etc.). Das einzige „Besondere“ ist der Aufruf onsubmit, der die Daten später verschlüsseln wird. Die Variable „this“ steht hier für das Formular, das abgeschickt werden soll.

<form method="post" onsubmit="encrypt_form(this)">
	<label for="user">Benutzer:</label>
	<input id="user"type="text" name="user" value="" />
	<label for="pass">Passwort:</label>
	<input id="pass" type="password" name="pass" value="" />
	<input type="submit" value="Login" />
</form>

Die Post verschicken

Beim Javascript habe ich mich für die wunderbare Lösung von Dr. Herbert Hanewinkel entschieden, weil sie einfach einzusetzen ist und alles mitbringt, was wir benötigen. Alle Scripte stehen unter GPL Lizenz. Meine Erweiterungen stehen unter WTFPL. Die einzelnen Teile zu erklären, würde sicher den Rahmen. Seine Scripte habe ich nur leicht überarbeitet, damit sie nach dem Google Closure Compiler noch funktionieren. So erhalten wir eine Datei, die wir einfach in unsere Seite einfügen können. Die Copyrighthinweise befinden sich im header, der gnupg.js.

Um die Scripte zu nutzen, kopiert Ihr zunächst die gnupg.js in den Ordner, indem auch das Formular liegt. und fügt diesen Schnipsel in Eure Seite ein. Der Publickey in Zeile 14 ist unser Publickey von oben (key.pub) mit base64_encode() bearbeitet. Ihr könnt den Schlüssel auch mit base64_encode(file_get_contents('key.pub')) lesen und ausgeben. So hab ich das auch in der Demo gemacht.

<script type="text/javascript" src="gnupg.js"></script>
<script type="text/javascript">
function encrypt_form(form) {
	var fields=form.getElementsByTagName("input");
	var data = '';
	for(var i=0;i<fields.length;i++)
	{
		if(fields[i].name!='')
		{
			data+=fields[i].name+'='+encodeURIComponent(fields[i].value)+"&";
			fields[i].value="";
		}
	}
	var pu=new getPublicKey(r2s("LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tClZlcnNpb246IEdudVBHIHYxLjQuMTAgKEdOVS9MaW51eCkKCm1RSU5CRTRrMUZBQkVBQ1l2STZKZFcwSWZCRVhuNzAzcURCRzVjcE81a3loM05Yd05jSThwaUwrSm9MV1J1QTYKQ3lkcUFuc2x2eGRBQ1ZFZkc2NDVlY2FCbWpaZ0szdCt0NVZFam4yM3c2WlRpU3RKWVhxVjk0VVVueUw3aDFoYwp6U1AxOGJVNWJuRjJtcjZ5QlZMQ0FFM09VSjE2UHdUczhKMU9ObTJZZW40VTE3QUpJV2NGU0owdjN3SlUyNmtMClVzdEY0Mm81UDVXc1M1R0NWTlZGSnhCQXdIeE9hTHVaOEVVVnZCOEpreGMzVytYVXhHSXViNkZMMXZnazBJVXYKWklxc1lqcElsd1hJWW1QeWthVEJQUFJEc1FPTk9iWnpTVUdGTmxwZnRQWisyZ21TUkpRa2gwdkhWdlFEaEg1UQpoWkZ6d3hod0I5OFo3K2plRkZOK1JJbWZsRmJ3UUlVU1JKNEpwSis0Rzg0YkdMQUp5R1pCTllJelBqdXlNcEp6Cng4bnFwTlVGYVBKUFJ2S1h6SlVFN0kzQ0h1dlNScFFCMDI2RitNbkRJN21GK294T0V3WGoxeGMvSW1zeDhQS1QKZ3prVERlL3hCN3pnZHF2WTNXTmN1Sm1UcXlsTjVjUEhSRDRYazBvNmRBQlM0V1dQUVBZcnV1Q2tnM3J6cWt1NwpQZGl1WHJGT0NOT1B6TlVIMzlPeDVtaTZlWm1saU1tWEF1ZFRzd3Q4T1JtTU13bWQ2WmhlOSs0UkJ2K1FnZkRWCkk1TUZZMS82T3I3Q3Z4NDQ4dFZ6NUt0YmxLYWgrT3duQnJIZVFJYjMxNTVLZUxzSEliNXd0U2M5cHBIMW1ETTEKL29QUFAxcFBJaG1qRGZXVTRDZlkzbVJsbWdqZVlITWZ5ams5cityK1ZsTTEwaWdrL05lcHhjeENrUUFSQVFBQgp0QTFOWldsdVYyVmljMlZ5ZG1WeWlRSTRCQk1CQWdBaUJRSk9KTlJRQWhzREJnc0pDQWNEQWdZVkNBSUpDZ3NFCkZnSURBUUllQVFJWGdBQUtDUkJFak1Sa0NjbVNuTk9VRUFDWW01b1JXTTZBbThFRytSM3VENGJ6TWpyZm1SOFAKemViWHM5K3p6Z1JjT3cvdEpRYjE0L1AxOWUvN1owcXBYaWxQaVYvRHR4YnFqaExEUTNwc2p1NlRxMG5kc1B3KwpqbDhRVGY5T090L2hDOXk2VlNTazhMdjJ4T2VBZ0NUQ1Z1b0E3YS9vWERyUGtTcWxoMmQrS0M4R1NaNGlobHY4CmpXcThBeEYzN3NySVRPZHh6SDk3KzNIcXpMQ1VWUmJCMkRvbzJOeHdsZWVmMXNwMHJRalIwU3J6cU1rRWRGZ0kKd1doazFWNEZJUndTb3hDSkJITHpJNkw0RTJsUXpDTDEvaFlpdWdINkVCNDJtUXloS1d0QWZoQzdvUDlpRU82MQo1ZWlBdTRPRkx2dzlKcnY1TWpuTktldUwwZ1pGMXd3QXlLNXVMWFBCaTQxN3VGWW5JbEg1RVlXdXk3L3l0MWppCnhHTDZtTiszTVYrZzg4SEptWUQrcUpzSDhnelpWdkNvVVd4UkN6cG5KazZHbGcvZWtDaVNDdjc0V0RjQjZZcFUKOUxxQm1UZEIvWFdzYmI5b1U4VC80dURmbGhhWklnY3p0MkxFWXdTalpIOEJRTnFlRm9yVEYyTXdOYStaV3AyMgpFZnAvYnR5NmdKMjgvTWRXMXphTnRLd1BFT3p6bmM4cEtIb0lwazF6alJUSFZIU3dIb1p1Z2ZrNVBLYlNBQ1pvCnJUZWI3N3ZoYVR1MnVxSkc1K2ZIWFVWeDcrMlpYMW92VG5RT3dUMmx4Q0daUkEyd1pheTFid1o1bzlXZkdpdXQKUW5hbkJqNzJUai9uNjZtMmxjTkZQVTRMWHMyeEY4TFg5bTQzeEZ6QStqbGJPd0dQaU0zYmZyeHpMZkZlUkI3aApUY2F4YnJ4UmdCbis4cmtDRFFST0pOUlFBUkFBMDVNZTBKcWxzKy8xWTAzSE02NUtuQ3JqU3cvUGVrbVZRU1ZFCnEvcUFKK3BPbDQ0RTVINzJ0YXZYWEhLVkZidjd3d2lRVHRjbmNDdDBJVTVxcUtHTUZIdXBiZzE3T3EraitmMTEKMGYrakdsSGRWVi9sd1h5S051b1lPcHNjV0Y2cGtDUTdYK1dpTjQ5RDdPOXFUL01ocUI5Q2hDUzBMblV5cmJ1Ygo3bWRFNUlQeXhlQjlVcCsvbzNWSVVMRHoreDFaWGZaVjA2OENCQTRWNUtpSXdnN1ExNFBpdGZOVjVxMkQ4bTBUClJFemFGVWxSUmdMRGRmOXNOcXpzWTUyamNhNG4reDRVSlBocTZ4WEhRV1d0ZlBQS3JPTmRCOVpjV0hka2poUWkKdEEveitwU0ZyTllOd2Z6SGNBU2l2b1lXczAyQ3Q5T0hvUk5ReFIrL25YUjBGNTRVSjZCUklyaTdzRU52bHBJVQoxeWpkUFVuZXhZQ3NNemx1bDdReFVhRTRqUTQ1MDZGWnR5eUpXMXZES3MxdStTb0swVEwzRGpTR3QwNjcxU1kzCmUvWjlJVWRZVFZNYjBWR1ByTDBpcFUvT0tTaUhYRjByOWp4b2dwWGp4TTRmWFhHa2FkTE8vQlQyUWRuMFlvVTEKc1Q2WFpKQ2dVZkJJbW44cTFaSkpiVFFuc25HZlFpMFMwdkZ4RFFVSDQ4MzIxTTFZRzZXZ2lsc0piMkVTRldNVApyTklZVDBPZUszZy9VSkcyOGhKNXAxWU5HS2JHZjBNMmlmTFBGUldLM1ZZY3B6dnJyVVFsK0FISmVxWkZWYXQxCjdSNVRzQU1LK1ViL0tnM3Q2SHZuT3Jmd0k4eSttUXBNanJhZEV0Z0xsakRWYUhsTktOcHpxdURmOXB6dSt0UmYKSDlDWVg1MEFFUUVBQVlrQ0h3UVlBUUlBQ1FVQ1RpVFVVQUliREFBS0NSQkVqTVJrQ2NtU25PalFELzlUenhzYgpSNWNLSm9mUWlUcEh1TkpvUmhjSEZnNTcvUU1yMU1BbGlQYy9lVEdqUWV6R1lXbWJzVlNUV1BLTnpYbHJJZkVBClB4eW9IQkJsaXJheUZmeDBFSnFtZ0J3NHdiWld4WUJsOWovK1dpdGJqcnZVNWdnNE9ZVHpyeVpBcU5kaklBMEgKK0VTSzE0T3ZWb2wrODhsa3VGZmxOeDMxdjZmMWJ5ckZmdk9NOFBlNUsyaGp3T1JPcDRjbFlMT3ByQWpONEpmawowWGxWcjFLZ2l3NmdMbHFPdHhiOHhsZTY5VEw0dUdmYTJwcU1zY0F6SGwzMHVXU0lqWFMxcnRza2RMN0EzRXh2CkhRUWlOMDlRSWVsTXB3OTByZG1UUTVabXdCQnN5NWZ3Yy9abHhDNnR1ZzduQU1ZUlBtRDZJemxxN3lSUC9rMk8KTkdnN2EzQWZMQXRib1JYSWxUTHU1ajdIZ0E2bmt1Y3Z3RlNUcUg4WElhWCtSK0sxYTB0WVlGM0x6UEtYS3FRVgpnZEExSHpiRDVCaTY4dXFvRVRqck5IMHZJVWhYZGxPRC9SdHpxancwdHZNVUlKUmxmUC9sY21PeTZMUmF4eEsvCk1zdFV5Q2RWYnpXMDIzay9FZDhRSEMxT0VOOGwwTC85dEFqcjljZ1BWcVB0RzFzUHhScEdOY3BGWUM4cGxLcHgKY2U2dHhRN3hlOFN5d0lFRnRUendqRXM5RENiWUtzUUtjQ3BBSXQvU1hJYTB1Q29BYkN4MnFLVGRPMTFjVHdOUgowdXVCWVVxbUttN3g2Z2pEbGZ5Nmo5Q3d4cnI5c25XMit4citWSFgyOEJ2OHNKR0ZuSTdPSkc0U3MyWWNBalpuClNKS29MQU9WNjg0bUMrcTlOd21HSHF4bmNsakg3cjdHYnovK3NnPT0KPVVNM2YKLS0tLS1FTkQgUEdQIFBVQkxJQyBLRVkgQkxPQ0stLS0tLQo="));
	var gpg=document.createElement('input');
	gpg.setAttribute('name', 'gpg');
	gpg.setAttribute('type', 'hidden');
	gpg.setAttribute('value', doEncrypt(pu.keyid,0,pu.pkey.replace(/\n/g,''),data));
	form.appendChild(gpg);
}
</script>

Das Script sieht schlimm kompliziert aus, ist aber eigentlich ganz einfach, denn es liest nur alle input Felder aus unserem Formular und fügt die Werte zu einem String zusammen. Bearbeitete Felder werden geleert. Wenn Ihr selects oder textareas benötigt, müsst Ihr es noch anpassen. Danach wird der String mit dem öffentliche Schlüssel gesichert und ein neues Feld angelegt, indem die verschlüsselte Nachricht hinterlegt wird. Danach ist das Script fertig und das Formular wird abgeschickt.

Die Post ist da

Hier noch eine einfache Möglichkeit, die Daten zu lesen. Das Verfahren kennen wir ja schon aus unserer test.php von oben. Die Werte für Fingerabdruck und Passwort müsst Ihr natürlich wieder ändern. Die entschlüsselte Nachricht findet sich dann in der Variable $post, mit der Ihr ganz normal weiter arbeiten könnt.

Sollte der Benutzer Javascript deaktiviert oder blockiert haben, werden die Daten unverschlüsselt gesendet, für einen Fallback müssten wir dann nicht $post, sondern $_POST benutzen. Da muss jeder für sich abwägen, was ihm wichtig ist und ob er das zulassen möchte. Warnhinweise wären z. B. mit <noscript> über dem Formular möglich.

<?php

if(isset($_POST) && !empty($_POST))
{
	echo '<h3>$_REQUEST</h3>';
	print_r($_REQUEST);

	putenv("GNUPGHOME=/home/webserver/.gnupg");
	$res = gnupg_init();
	gnupg_adddecryptkey($res, "EB51FBD8E2A1081D40B94D74448CC46409C9929C", "**********");
	parse_str(trim(gnupg_decrypt($res, $_POST['gpg'])), $post);
	echo '<h3>Entschlüsselt</h3>';
	print_r($post);
}
?>

Was geht nicht?

Die Signierung durch eine externe Stelle ist nicht möglich und damit fehlt eine nicht ganz unwichtige Komponente im Prozess, denn das Verfahren könnte theoretisch kompromittiert werden. Jemand könnte das Zertifikat austauschen und dann die Leitungen abhorchen. Wie wahrscheinlich das ist, muss jeder selbst beurteilen. Wenn ich Zugriff auf einen Server erlangen würde, stände das ganz unten auf meiner Todo-Liste. Mir eingegebene Passwörter irgendwo versteckt an meine russische E-Mail Adresse schicken zu lassen wäre schneller und effizienter. Eine andere Möglichkeit wäre, die DNS so umzubiegen, dass man die Daten unverschlüsselt sendet, aber auch hier braucht man einen wesentlichen Mehraufwand.

Übrigens: Die Sicherheit von TLS hängt nicht hauptsächlich von der Signierung ab, sondern vom Webmaster. Selbstsignierte Zertifikate sind nicht unsicherer, auch wenn der Browser schlimme Warnungen anzeigt. Der einzige Nachteil ist, dass man dieses Zertifikat nicht umfassend widerrufen kann. Wenn sich umgekehrt ein Serverbetreiber nicht um die Sicherheit seiner Zertifikate kümmert, dann nützt auch die grünste Leiste der Welt nichts.

Ein weiterer Schwachpunkt ist, dass das Passwort in der PHP Datei hinterlegt sein muss. Allerdings sind auch Serverzertifikate selten mit einem Passwort versehen, denn dann müsste man es ja beim Start des Webservers eingeben. Von daher relativiert sich auch dieses Risiko. Ein wirklicher Schwachpunkt ist aber, das Cookies nicht mit geschützt werden. Auch da muss man mit zusätzlichen Maßnahmen nachhelfen, entweder innerhalb von PHP oder mit der Suhosin Erweiterung.

Fazit

Daten sicher zu übertragen ist immer sinnvoll, wenn es um sensible Informationen geht. Die beschriebene Methode ist ein sehr einfaches Verfahren, um Informationen sicher zu übertragen. Es ersetzt in keinem Fall TLS! Nichtsdestotrotz bietet es einen sehr guten und sicheren Schutz gegen unerwünschte Abhörmaßnahmen.

Written by Oliver

Juli 25th, 2011 at 9:41 am

Posted in Javascript,PHP

Tagged with , , ,

5 Responses to 'TLS/SSL für Heimwerker'

Subscribe to comments with RSS or TrackBack to 'TLS/SSL für Heimwerker'.

  1. Danke für diesen kleinen Einblick, ich glaube ich bookmarke mir das mal; für Server auf denen man kein TLS verwenden kann ist das auf jeden Fall interessant.

    Rasioc

    25 Jul 11 at 11:17

  2. Sehr coole Erklärung … detaillierte Anleitung. GnuPG für PHP hatte ich bis jetzt noch nicht gehört, klingt aber cool. Müssten wir auch mal Zend_Form beibringen 😉

    Denis

    26 Jul 11 at 09:39

  3. Unser Ralf hat gar nichts geschrieben – er wollte doch Lösungen haben, wenn irgendwas nicht umsetzbar ist!? Nun, hier ist eine.

    Oliver

    26 Jul 11 at 12:18

  4. […] wurde ich vom Tutorial TSL/SSL für Heimwerker von Oliver Sperke und vieles ist auch daraus […]

  5. […] das so wie hier und hier gemacht. […]

Leave a Reply

You can add images to your comment by clicking here.