<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>PHP hates me - Der PHP Blog &#187; Sicherheit</title>
	<atom:link href="http://www.phphatesme.com/archives/category/sicherheit/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.phphatesme.com</link>
	<description>PhpHatesMe, but that&#039;s ok!</description>
	<lastBuildDate>Tue, 07 Feb 2012 06:00:42 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>HashDoS Angriff legt (unter anderem) PHP lahm</title>
		<link>http://www.phphatesme.com/blog/sicherheit/hashdos-angriff-legt-unter-anderem-php-lahm/</link>
		<comments>http://www.phphatesme.com/blog/sicherheit/hashdos-angriff-legt-unter-anderem-php-lahm/#comments</comments>
		<pubDate>Wed, 28 Dec 2011 23:32:44 +0000</pubDate>
		<dc:creator>PHP Gangsta</dc:creator>
				<category><![CDATA[phmnetwork]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Sicherheit]]></category>

		<guid isPermaLink="false">http://www.phpgangsta.de/?p=4109</guid>
		<description><![CDATA[Ich bin leider die letzten 2 Tage nur wenige Stunden dazu gekommen die Live-Streams vom 28. Chaos Communication Congress (28C3) zu schauen, aber bzgl. PHP ist heute Nachmittag ein interessanter Talk gehalten worden mit dem Thema Effective Denial of Service attacks against web application platforms dem ich hier einen kurzen Artikel widmen werde. Es geht darum [...]<br /><br /> Ähnliche Artikel:<ol><li><a href="http://www.phpgangsta.de/pdt-2-1-unter-windows-mit-subclipse-svn-client" rel="bookmark" title="PDT 2.1 unter Windows mit Subclipse SVN Client">PDT 2.1 unter Windows mit Subclipse SVN Client</a></li></ol>]]></description>
			<content:encoded><![CDATA[<p>Ich bin leider die letzten 2 Tage nur wenige Stunden dazu gekommen die <a href="http://28c3.fem-net.de/" >Live-Streams</a> vom <a href="http://events.ccc.de/congress/2011/wiki/Main_Page" >28. Chaos Communication Congress (28C3) </a>zu schauen, aber bzgl. PHP ist heute Nachmittag ein interessanter Talk gehalten worden mit dem Thema <a href="http://events.ccc.de/congress/2011/Fahrplan/events/4680.en.html" >Effective Denial of Service attacks against web application platforms</a> dem ich hier einen kurzen Artikel widmen werde.</p><p>Es geht darum wie PHP (und die anderen anfälligen Sprachen auch) Hash-Tabellen erstellen und verwalten. Die hier interessante Hash-Tabelle ist das $_POST Array, das man von außen füllen kann, und das anfällig ist wenn man nur genügend &#8220;passende&#8221; Datensätze reinfüllt. Der Algorithmus der die Hash-Tabelle befüllt wird nämlich langsamer sobald Kollisionen der Keys auftreten. Schickt man also beispielsweise 300KB POST-Daten an ein PHP-Script ist eine schnelle CPU damit ca. 30 Sekunden unter Volllast. Bei 8MB (dem Standard-Maximum für POST-Daten in der php.ini) wären es immerhin schon 5 Stunden, die die CPU benötigt um die Hash-Table zu füllen. Man kann also mit einer relativ kleinen DSL-Leitung einigen Schaden anrichten. Mit einer Gigabit-Leitung kann man so 10.000 CPU-Kerne dauerhaft beschäftigen.</p><p><span id="more-4109"></span>Etwas Abhilfe schaffen da die Einstellungen max_input_time und max_execution_time, die je nach Distribution 30 Sekunden, 60 Sekunden bzw. nicht beschränkt sind. Man müßte also mehrere kleine Anfragen schicken und kann nicht die 8MB ausnutzen. mit ca. 500KB kann man einen CPU-Kern dann etwa eine Minute beschäftigen.</p><p>Das Problem ist wohl seit 2003 bekannt, Perl hat es damals behoben indem in die Generierung des Hash-Index auch Zufall mit einfließt, und nicht nur der Key die Hash-Position bestimmt. Neben PHP sind übrigens auch Java, Apache Tomcat, Apache Geronimo, Jetty, Oracle Glassfish, ASP.NET, Python, Plone, CRuby 1.8, JRuby, Rubinius und v8 (Node.JS) betroffen (<a href="http://www.ocert.org/advisories/ocert-2011-003.html" >Details zu betroffenen und gefixten Versionen</a>).</p><p>Abhilfe schafft beispielsweise die <a href="http://www.hardened-php.net/suhosin/" >PHP-Extension Suhosin</a>, mit der die <a href="http://www.hardened-php.net/suhosin/configuration.html#suhosin.post.max_vars" >Anzahl an POST-Variablen</a> beschränkt werden kann (Standard ist 200). Seit 3 Wochen gibt es auch einen <a href="http://svn.php.net/viewvc?view=revision&amp;revision=321003" >Patch für PHP</a> der eine neue php.ini Variable max_input_vars (Standard 1000) einführt, dieser Patch wird enthalten sein in PHP &gt;=5.3.9 und &gt;=5.4.0 RC4</p><p>Ein <a href="https://cryptanalysis.eu/blog/2011/12/28/effective-dos-attacks-against-web-application-plattforms-hashdos/" >sehr hilfreicher Artikel bei cryptanalysis.eu</a> erklärt noch einige Details. Natürlich empfiehlt es sich auch das <a href="http://www.youtube.com/watch?v=_EEhviEO1Vo" >aufgezeichnete Video des Talks</a> zu schauen. Aktuell ist es ein PreRelease, das finale Video wird wahrscheinlich erst morgen oder übermorgen erscheinen nehme ich an.</p><p>Aktuell werden wohl noch keine großflächigen Angriffe beobachtet, aber wer auf der sicheren Seite sein will installiert sich Suhosin falls nicht eh schon geschehen. Aber Achtung, einige Restriktionen sind zu streng und könnten die Benutzung der Applikation beeinflussen die auf hohe Werte einiger Einstellungen angewiesen ist, also bitte vorher testen. Oder noch etwas gedulden und bald auf PHP 5.3.9 bzw. PHP 5.4.0 updaten.</p><p><strong><em>EDIT: php.net ist langsam bzw. zeitweise nicht erreichbar&#8230;</em></strong></p><p><strong>EDIT: Der <a href="http://ftp.snt.utwente.nl/pub/misc/28c3/mp4-h264-HQ/28c3-4680-en-effective_dos_attacks_against_web_application_platforms_h264.mp4.torrent" >torrent zum offiziellen Release des Videos</a>.</strong></p><p><strong>EDIT: <a href="http://koto.github.com/blog-kotowicz-net-examples/hashcollision/kill.html" >Demo-Webseite</a> incl. <a href="https://github.com/koto/blog-kotowicz-net-examples/tree/master/hashcollision" >Quelltext</a></strong></p> <br/><br/><p>Ähnliche Artikel:</p><ol><li><a href='http://www.phpgangsta.de/pdt-2-1-unter-windows-mit-subclipse-svn-client' rel='bookmark' title='PDT 2.1 unter Windows mit Subclipse SVN Client'>PDT 2.1 unter Windows mit Subclipse SVN Client</a></li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.phphatesme.com/blog/sicherheit/hashdos-angriff-legt-unter-anderem-php-lahm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Die Reporting-Funktion der Content-Security-Policy (CSP)</title>
		<link>http://www.phphatesme.com/blog/sicherheit/die-reporting-funktion-der-content-security-policy-csp/</link>
		<comments>http://www.phphatesme.com/blog/sicherheit/die-reporting-funktion-der-content-security-policy-csp/#comments</comments>
		<pubDate>Tue, 30 Aug 2011 06:52:28 +0000</pubDate>
		<dc:creator>PHP Gangsta</dc:creator>
				<category><![CDATA[phmnetwork]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Sicherheit]]></category>

		<guid isPermaLink="false">http://www.phpgangsta.de/?p=3341</guid>
		<description><![CDATA[CSP hatte ich vor fast 2 Jahren bereits vorgestellt, mittlerweile hat es eine gute Verbreitung gefunden, sodass wir uns nochmals die Details anschauen. CSP ist ein Header, den der Server an den Browser schickt, und darin festlegt, von wo Javascripte, Bilder, CSS, Media-Dateien und mehr geladen werden dürfen. Mit sinnvollen Einstellungen ist es möglich, Cross [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.phpgangsta.de/xss-angriffe-erschweren-mit-csp-der-neuen-idee-von-mozillafirefox" >CSP hatte ich vor fast 2 Jahren bereits vorgestellt</a>, mittlerweile hat es eine gute Verbreitung gefunden, sodass wir uns nochmals die Details anschauen. CSP ist ein Header, den der Server an den Browser schickt, und darin festlegt, von wo Javascripte, Bilder, CSS, Media-Dateien und mehr geladen werden dürfen. Mit sinnvollen Einstellungen ist es möglich, <a href="http://de.wikipedia.org/wiki/Cross-Site_Scripting" >Cross Site Scripting (XSS)</a> sowie <a href="http://de.wikipedia.org/wiki/Clickjacking" >Clickjacking</a> zu verhindern, eine dieser essenziell wichtigen Einstellungen ist das Verbot von Inline-Javascript. Falls also ein Angreifer Javascript beispielsweise in die Datenbank einfügen kann, und bei der Ausgabe nicht oder falsch escaped wird, wird das Inline-Javascript das der Angreifer platziert hat nicht ausgeführt, XSS ist effektiv unterbunden.</p>
<p>In der Apache Konfiguration kann das beispielsweise so aussehen:</p>
<pre class="brush: plain; title: ; notranslate">&lt;VirtualHost *:80&gt;
    DocumentRoot /path/to/wwwroot
    ServerName domain.de

    Header add X-Content-Security-Policy &quot;allow 'self'; img-src images.domain.de; script-src static.domain.de;&quot;
&lt;/VirtualHost&gt;</pre>
<p>oder hier mittels PHP gesetzt:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
header(&quot;X-Content-Security-Policy: allow 'self'; img-src images.domain.de; script-src static.domain.de;&quot;);</pre>
<p>Sollten nun Bilder oder Javascripte eingebunden sein die nicht von den angegebenen Domains kommen wird der Browser sie blockieren und nicht laden. Es gibt neben img-src und script-src auch noch frame-src, xhr-src <a href="https://developer.mozilla.org/en/Security/CSP/CSP_policy_directives#Supported_policy_directives" >und weitere</a>.</p>
<p><span id="more-3341"></span>Wir können nun also alle gültigen Quellen für die externen Ressourcen definieren. Ein hilfreiches Zusatzfeature ist das Reporting, das den Browser anweist, im Falle einer CSP-Verletzung eine bestimmte URL aufzurufen. Es ist auch möglich, nur das Reporting zu aktivieren. Falls also eine unerwartete Ressource geladen wird von einem fremden Server, können wir Alarm schlagen und das Problem analysieren und beseitigen. Ein Reporting-Header sieht beispielsweise so aus:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
header(&quot;X-Content-Security-Policy-Report-Only: allow 'self'; img-src images.domain.de; script-src static.domain.de; report-uri /violation.php&quot;);</pre>
<p>Der Header-Name hat sich leicht geändert, eine Reporting-URI ist hinzugekommen, ansonsten ist alles gleich geblieben. Im Unterschied zum normalen Header sorgt der Report-Only-Header dafür dass nichts blockiert wird, nur die Verletzungen werden gemeldet. Ideal falls man nur XSS entdecken möchte, es ist auch hilfreich wenn man gerade den richtigen CSP-Header erstellt und produktiv schaltet, denn man kann beide Header senden, dann wird blockiert und reported. Eigentlich sollte der Reporting-Only Header immer da sein, um Rückmeldungen zu erhalten und auf Bedrohungen reagieren zu können.</p>
<p>Wie sieht nun die violation.php aus?</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
$json = file_get_contents('php://input');
if ($json === false) {
    throw new Exception('Bad Request');
}

$csp = json_decode($json, true);
if (is_null($csp)) {
    throw new Exception('Bad JSON Violation');
}

$msg = &quot;Request: &quot;.$csp['csp-report']['request'].&quot;\n&quot;.
       &quot;Request: &quot;.$csp['csp-report']['blocked-uri'].&quot;\n&quot;.
       &quot;Request: &quot;.$csp['csp-report']['violated-directive'];
// log or mail $msg now</pre>
<p>Die Reporting-Informationen kommen als RAW POST JSON Daten. Wir lesen also von der Standard-Eingabe, JSON-decodieren den Text und loggen oder versenden dann die wichtigen Informationen per E-Mail. So sind wir immer auf dem aktuellen Stand bezüglich der CSP-Verstöße.</p>
<p>Hier noch ein Beispiel, und wie es im Firebug dargestellt wird:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
header(&quot;X-Content-Security-Policy: allow 'self'; img-src images.domain.de; script-src static.domain.de&quot;);
header(&quot;X-Content-Security-Policy-Report-Only: allow 'self'; img-src images.domain.de; script-src static.domain.de; report-uri /violation.php&quot;);
?&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;script type=&quot;text/javascript&quot;&gt;
            alert('CSS');
        &lt;/script&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;img src=&quot;http://www.phpgangsta.de/wp-content/uploads/update-300x225.jpg&quot; /&gt;
    &lt;/body&gt;
&lt;/html&gt;</pre>
<p>Die Webseite bleibt komplett weiß, weder das Javascript wird ausgeführt noch das Bild wird angezeigt.</p>
<p><img class="alignnone size-full wp-image-3403" title="CSP im Firebug" src="http://www.phpgangsta.de/wp-content/uploads/cspfirebug.png" alt="" width="648" height="165" /></p>
<p class="wp-flattr-button">
<p><a href="http://www.phpgangsta.de/?flattrss_redirect&amp;id=3341&amp;md5=dee005270883d32c2935b15831b02d97" title="Flattr" ><img src="http://www.phpgangsta.de/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phphatesme.com/blog/sicherheit/die-reporting-funktion-der-content-security-policy-csp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Das Problem mit HEAD Requests in PHP</title>
		<link>http://www.phphatesme.com/blog/sicherheit/das-problem-mit-head-requests-in-php/</link>
		<comments>http://www.phphatesme.com/blog/sicherheit/das-problem-mit-head-requests-in-php/#comments</comments>
		<pubDate>Thu, 25 Aug 2011 11:53:00 +0000</pubDate>
		<dc:creator>PHP Gangsta</dc:creator>
				<category><![CDATA[phmnetwork]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Sicherheit]]></category>

		<guid isPermaLink="false">http://www.phpgangsta.de/?p=3363</guid>
		<description><![CDATA[Ich bin gerade auf ein interessantes Verhalten gestoßen das eventuell große Probleme bereiten kann. Wahrscheinlich nur sehr wenige von euch werden das hier wissen, trotzdem ist es sehr interessant und provoziert eventuell Probleme und Sicherheitslücken. Das hier vorgestellte Verhalten ist wahrscheinlich kein Problem von PHP sondern eventuell vom Webserver, aber ich weiß es nicht genau. [...]]]></description>
			<content:encoded><![CDATA[<p>Ich bin gerade auf ein interessantes Verhalten gestoßen das eventuell große Probleme bereiten kann. Wahrscheinlich nur sehr wenige von euch werden das hier wissen, trotzdem ist es sehr interessant und provoziert eventuell Probleme und Sicherheitslücken.</p>
<p>Das hier vorgestellte Verhalten ist wahrscheinlich kein Problem von PHP sondern eventuell vom Webserver, aber ich weiß es nicht genau. Vielleicht kann ja mal jemand mit Tomcat oder nginx dieses Problem nachstellen.</p>
<p>Wir nehmen folgendes Script als Beispiel:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
file_put_contents('/tmp/outp', '1');

echo 'start';
file_put_contents('/tmp/outp', '2', FILE_APPEND);
echo 'ende';</pre>
<p>Ich glaube ihr stimmt mir alle zu wenn ich behaupte: Das Script erstellt immer eine Datei mit dem Inhalt &#8220;12&#8243;. Es kann zum Beispiel nicht passieren dass nur &#8220;1&#8243; in der Datei steht.</p>
<p>Falsch gedacht. Ein Client (Browser) kann einen HEAD Request zum Webserver(Apache) schicken, d.h. der Client ist nur an den Header-Informationen der Antwort interessiert. Was tut der Apache? Er startet das PHP Script, und bricht es bei der ersten Ausgabe ab!! Denn dann kann man mit PHP nicht mehr die Header verändern, und der Apache spart CPU etc. und stoppt das PHP-Script.</p>
<p>Was bedeutet das für unser Beispiel-Script? In der Datei /tmp/outp steht plötzlich nur &#8220;1&#8243; drin. Man kann sich nun überlegen was das für seine eigene Applikation bedeutet. Man schaue sich dieses Beispiel an:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php
session_start();
$_SESSION['admin']=1;

if (!isset($_POST['pass']) || $_POST['pass']!='somepassword') {
    echo '&lt;b&gt;Wrong or empty password.&lt;/b&gt;&lt;br&gt;';
    $_SESSION['admin']=0;
} else {
    echo 'logged in';
}</pre>
<p>Ich hoffe niemand programmiert so, aber ihr sehr das Problem: In der Session wird erstmal ein Flag gesetzt, das bei falschem Passwort wieder zurückgesetzt wird. Normalerweisse funktioniert das super, es sei denn jemand schickt einen HEAD Request wird mit falschem Passwort, dann wird das Script beim echo gestoppt, in der Session ist der Benutzer dann eingeloggt!</p>
<p>Oder stellt euch vor ihr habt ein Script, das eine CSV-Datei erstellt, zum Beispiel so:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php

$data = &lt;datenbankabfrage&gt;

foreach ($data as $d) {
    file_put_contents('/tmp/csv.csv', $d['id'] . ';' . $d['name'] . &quot;\n&quot;, FILE_APPEND);
    echo &quot;.&quot;;
}</pre>
<p>Falls jemand das Script mit der Methode HEAD aufruft wird eure CSV-Datei nur eine Zeile enthalten, sprich defekt sein, euer System das von der Vollständigkeit der CSV-Datei ausgeht wird Fehler produzieren.</p>
<p>Was kann man gegen dieses Problem tun? Man rechnet einfach immer damit dass ein Script auch abbrechen kann (wenn der Apache abstürzt, das Netzteil durchbrennt), man nutzt Output-Buffering (ob_start() etc.) oder deaktiviert HEAD-Requests komplett.</p>
<p>Eventuell habt ihr weitere interessante Beispiele was dadurch kaputt gehen kann. Das ist jedenfalls ein Problem über das ich mir so noch nie Gedanken gemacht habe. Das Problem habe ich <a href="https://students.mimuw.edu.pl/~ai292615/php_head_trick.pdf" >in diesem PDF</a> gefunden.</p>
<p class="wp-flattr-button">
<p><a href="http://www.phpgangsta.de/?flattrss_redirect&amp;id=3363&amp;md5=7e4c155a761dbd364147c13245b4900a" title="Flattr" ><img src="http://www.phpgangsta.de/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phphatesme.com/blog/sicherheit/das-problem-mit-head-requests-in-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Manipulationen erkennen – Bemerken dass man gehackt wurde</title>
		<link>http://www.phphatesme.com/blog/sicherheit/manipulationen-erkennen-%e2%80%93-bemerken-dass-man-gehackt-wurde/</link>
		<comments>http://www.phphatesme.com/blog/sicherheit/manipulationen-erkennen-%e2%80%93-bemerken-dass-man-gehackt-wurde/#comments</comments>
		<pubDate>Wed, 17 Aug 2011 07:42:36 +0000</pubDate>
		<dc:creator>PHP Gangsta</dc:creator>
				<category><![CDATA[phmnetwork]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Sicherheit]]></category>

		<guid isPermaLink="false">http://www.phpgangsta.de/?p=3265</guid>
		<description><![CDATA[In viele Webseiten wird heutzutage eingebrochen und es werden Änderungen an der Webseite durchgeführt. Das kann die selbst programmierte Webseite sein bei der man eine Lücke eingebaut hat, das kann aber auch ein installiertes WordPress oder Joomla sein. Häufig sind solche Angriffe nicht geziehlt, sondern werden mittels automatischer Scripte durchgeführt, die dann auf allen anfälligen [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-medium wp-image-3266" title="Sherlock Holmes" src="http://www.phpgangsta.de/wp-content/uploads/holmes-287x300.jpg" alt="" width="218" height="228" /></p>
<p>In viele Webseiten wird heutzutage eingebrochen und es werden Änderungen an der Webseite durchgeführt. Das kann die selbst programmierte Webseite sein bei der man eine Lücke eingebaut hat, das kann aber auch ein installiertes WordPress oder Joomla sein.</p>
<p>Häufig sind solche Angriffe nicht geziehlt, sondern werden mittels automatischer Scripte durchgeführt, die dann auf allen anfälligen Servern kleine Änderungen an den Dateien durchführen:</p>
<p>- Phishing Webseiten werden auf den Server gelegt<br /> &#8211; in die Webseite wird bösartiger Code eingebaut der mittels Flash, Javascript, Windows Media Player oder anderen Techniken versucht einen <a href="http://de.wikipedia.org/wiki/Drive-by-Download" >Drive-By-Download</a> bei den Besuchern zu platzieren<br /> &#8211; die Webseite wird &#8220;nur&#8221; <a href="http://de.wikipedia.org/wiki/Defacement" >defaced</a>, sprich ein witziges Bild wird auf die Webseite gesetzt die den Besitzer blossstellen soll<br /> &#8211; an strategisch gut platzierte Stellen im Code werden mail() Aufrufe eingefügt die beispielsweise die Klartextpasswörter an den Angreifer senden<br /> &#8211; es werden kleine Scripte abgelegt wie beispielsweise <a href="http://sourceforge.net/projects/poxy/" >PHProxy</a> oder ein Spam-Mail-Script<br /> &#8211; heutzutage wird auch gern die .htaccess Datei verändert, mit der der Suchmachinen-Traffic auf eine andere Seite umgeleitet wird, beispielsweise so:</p>
<p><span id="more-3265"></span></p>
<pre class="brush: plain; title: ; notranslate">RewriteEngine On
RewriteCond %{HTTP_REFERER} .*google.*$ [NC,OR]
RewriteCond %{HTTP_REFERER} .*ask.*$ [NC,OR]
RewriteCond %{HTTP_REFERER} .*yahoo.*$ [NC,OR]
RewriteCond %{HTTP_REFERER} .*altavista.*$ [NC,OR]
RewriteCond %{HTTP_REFERER} .*msn.*$ [NC,OR]
RewriteCond %{HTTP_REFERER} .*netscape.*$ [NC,OR]
RewriteCond %{HTTP_REFERER} .*aol.*$ [NC,OR]
RewriteCond %{HTTP_REFERER} .*lycos.*$ [NC,OR]
RewriteCond %{HTTP_REFERER} .*search.*$ [NC,OR]
RewriteCond %{HTTP_REFERER} .*metacrawler.*$ [NC,OR]
RewriteRule .* http://hackerwebseite.de [R,L]</pre>
<p>Falls die Angreifer Dateien verändern oder hinzufügen können wir das mit einem geeigneten Programm erkennen. Falls der bösartige Code in die Datenbank geschrieben wird hilft die hier vorstellte Lösung nicht.</p>
<p>Die strategisch beste Lösung ist die Überwachung auf Betriebssystemebene. Dazu gibt es Programme wie die unten aufgeführten die eine Liste von Dateien und Ordnern abarbeiten und die Dateien auf Veränderungen prüfen. Standardmäßig sind das Dateien in denen häufig Rootkits installiert werden wie /usr/bin/sh, /usr/bin/ls, /usr/bin/ps usw. aber auch eigene Ordner können auf Änderungen überwacht werden. Bekannte Programme sind <a href="http://sourceforge.net/projects/tripwire/" >Tripwire</a>, <a href="http://aide.sourceforge.net/" >AIDE</a>, <a href="http://osiris.shmoo.com/" >Osiris</a>, <a href="http://www.la-samhna.de/samhain/" >Samhain</a>, <a href="http://sourceforge.net/projects/iwatch/" >iWatch</a>, und <a href="http://www.ossec.net/" >OSSEC</a>.</p>
<p>Was aber macht man wenn man ein Webhosting-Paket hat? In diesen Fällen kann man sein Webverzeichnis nicht von solchen Programmen überwachen lassen, sondern muss sich selbst darum kümmern, mit natürlich einigen Nachteilen.</p>
<p>Ich habe <a href="https://github.com/PHPGangsta/FileWatcher" >auf GitHub das Projekt FileWatcher</a> gestartet, eine PHP Klasse die Dateien und Ordner auf Änderungen überprüfen kann, und bei Änderungen Alarm schlägt. Wird dann so genutzt:</p>
<pre class="brush: php; title: ; notranslate">&lt;?php

require_once 'FileWatcher.php';

$fileWatcher = new FileWatcher();
$fileWatcher-&gt;readConfig('FileWatcher.config.php')
            -&gt;checkNow();</pre>
<p>Die Konfiguration könnte beispielsweise so aussehen (hier für ein Windows-System):</p>
<pre class="brush: php; title: ; notranslate">$config = array(
    'password'              =&gt; 'secretPassword',
    'includePaths'          =&gt; array('C:\\Temp', 'D:\\temp'),
    'excludeFolderList'     =&gt; array('C:\\Temp\\projekt'),
    'excludeExtensionList'  =&gt; array('jpg', 'png', 'pdf'),

    'hashMasterFilename'    =&gt; 'FileWatcher.MasterHashes.txt',
    'logFilename'           =&gt; 'FileWatcher.log',
    'overwriteMasterFile'   =&gt; true,

    'alertEmailAddress'     =&gt; 'alerts@domain.de',
    'alertEmailSubject'     =&gt; 'ALERT: File hashes on your server have changed',
    'alertEmailMethod'      =&gt; 'mail',  // mail or smtp
    'alertEmailSmtpServer'  =&gt; '1.2.3.4',
    'alertEmailSmtpUser'    =&gt; 'XXXX',
    'alertEmailSmtpPass'    =&gt; 'XXXX',
);</pre>
<p>Es ist die erste Version, man kann natürlich noch einige Features hinzufügen wie alternative Benachrichtigungswege (Jabber, SMS?), oder eine Änderungsprüfung anhand des Last-Modified-Dates statt einem SHA1-Hash, das dürfte bei vielen großen Dateien deutlich schneller sein.</p>
<p>Man könnte sich auch an Extensions wie <a href="http://www.php.net/manual/en/fam.installation.php" >FAM</a> oder <a href="http://www.php.net/manual/en/ref.inotify.php" >Inotify</a> heranwagen, interessant um sehr schnell Änderungen an Dateien mitzubekommen, aber dazu muss man diese Extensions auch installieren können.</p>
<p>In der README sind noch einige weitere ToDos.</p>
<p>Tut ihr irgendetwas in der Richtung, fremde Veränderungen auf euren Servern zu entdecken?</p>
<p>PS: Falls nur ein WordPress Blog betrieben wird hilft evtl. auch der Einsatz des <a href="http://wordpress.org/extend/plugins/wordpress-file-monitor-plus/" >Plugins File Monitor Plus</a>.</p>
<p class="wp-flattr-button">
<p><a href="http://www.phpgangsta.de/?flattrss_redirect&amp;id=3265&amp;md5=882e96b744e6553d209833c538c0b2ed" title="Flattr" ><img src="http://www.phpgangsta.de/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phphatesme.com/blog/sicherheit/manipulationen-erkennen-%e2%80%93-bemerken-dass-man-gehackt-wurde/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dieser Schlüssel zerstört sich in 30 Sekunden selbst</title>
		<link>http://www.phphatesme.com/blog/sicherheit/dieser-schlussel-zerstort-sich-in-30-sekunden-selbst/</link>
		<comments>http://www.phphatesme.com/blog/sicherheit/dieser-schlussel-zerstort-sich-in-30-sekunden-selbst/#comments</comments>
		<pubDate>Mon, 01 Aug 2011 07:34:18 +0000</pubDate>
		<dc:creator>Oliver Klee</dc:creator>
				<category><![CDATA[phmnetwork]]></category>
		<category><![CDATA[Sicherheit]]></category>

		<guid isPermaLink="false">http://www.phpgangsta.de/?p=3156</guid>
		<description><![CDATA[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. Nachdem ich ja in den letzten Wochen über den sicheren Umgang mit Passwörtern [...]]]></description>
			<content:encoded><![CDATA[<p><em>Gastartikel von Oliver Sperke.</em></p>
<p><em>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.</em></p>
<p>Nachdem ich ja in den letzten Wochen über den <a href="http://www.phpgangsta.de/passwortmythen-oder-%E2%80%9Ewas-du-schon-immer-uber-passworter-wusstest-aber-nie-zu-sagen-wagtest%E2%80%9C">sicheren</a> <a href="http://www.phpgangsta.de/schoener-hashen-mit-bcrypt">Umgang</a> mit <a href="http://www.phpgangsta.de/tlsssl-fur-heimwerker">Passwörtern</a> in Webprojekten erzählt habe, soll es heute mal um etwas anderes gehen (aber trotzdem um das Thema Sicherheit). Wenn man oft auf fremden oder eigenen Servern arbeitet, kommt man an <a href="http://www.openssh.com/">OpenSSH</a> eigentlich nicht vorbei. Und wenn man dazu noch so faul ist wie ich (und vermutlich die meisten von Euch auch), hat man keine dutzenden Dateien mit Passwörtern, sondern wickelt die gesamten Loginvorgänge mit Hilfe von <a href="http://de.wikipedia.org/wiki/Public-Key-Authentifizierung">öffentlichen und privaten Schlüsseln</a> ab. Dieses Verfahren ist nicht nur bequem, es bietet auch zusätzliche Sicherheit, da man nicht in Versuchung kommt, einfache Passwörter zu verwenden. Ausserdem ist die eigene Passwortliste schon von Haus aus verschlüsselt.</p>
<p>Das Verfahren hat aber für einen Serverbetreiber Nachteile. Der öffentliche Schlüssel muss auf dem Server hinterlegt werden. Ausserdem muss man sobald der Zugang nicht mehr benötigt wird, nachsehen, ob ein Benutzer sich vielleicht eigene Schlüssel hinterlegt hat und natürlich muss man ihm den Zugang manuell sperren.</p>
<p><span id="more-3156"></span>Alle diese Vorgänge sind lästig und zeitaufwendig und bergen Gefahren, vor allem dann, wenn man die Zugänge von vielen Benutzern verwalten muss. Schnell hat man eine Zeile in der <a href="http://www.eng.cam.ac.uk/help/jpmg/ssh/authorized_keys_howto.html">„authorized_keys“</a> Datei für einen Benutzer übersehen und handelt sich damit dauerhaft ungebetene Gäste ein. Seit OpenSSH 5.6 gibt es nicht nur die Möglichkeit, öffentliche und private Schlüssel zu hinterlegen, sondern den öffentlichen Schlüssel zu signieren. Dieses Verfahren der Signierung oder Zertifizierung bietet uns gewaltige Vorteile.</p>
<p>Der Server kann bei einer Signierung erkennen, ob ein Schlüssel nur für einen gewissen Zeitraum gültig sein soll oder schon abgelaufen ist und ob gewisse Rechte, z. B. zum <a href="http://www.jfranken.de/homepages/johannes/vortraege/ssh2_inhalt.de.html#ToC1">X11 Forwarding</a> oder <a href="http://www.jfranken.de/homepages/johannes/vortraege/ssh2_inhalt.de.html#ToC9">Port Weiterleitung</a> erteilt wurden oder nicht. Ausserdem müssen wir die Public Keys der Nutzer nicht mehr hinterlegen und unser Privatekey ist quasi unangreifbar. Dieses Verfahren benötigt fertig eingerichtet nicht mal mehr einen Login auf dem Server zur Erstellung neuer Zugänge.</p>
<h2>Wichtiger Hinweis und Ausgangssituation</h2>
<p><strong>Lest bitte erst den ganzen Text, damit Ihr nicht in der Mitte stecken bleibt. Wenn Ihr nicht regelmäßig auf Linuxsystemen arbeitet, dann richtet euch eine virtuelle Maschine ein, die Ihr nach Lust und Laune kaputt konfigurieren könnt. Das Verfahren nutze ich selbst auf meinen Servern, wenn Ihr Euch trotzdem aussperrt, dann ist das nicht meine Schuld, bei mir geht es ja. Man kann das Verfahren auch auf <em>einem Rechner</em> testen.</strong></p>
<p><strong>Falls Euer Zielrechner nicht greifbar für Euch ist, also irgendwo im Rechenzentrum steht, lasst die Passwortauthentifizierung an und loggt Euch zusätzlich auf einer anderen Konsole ein. Lasst das Fenster offen. Sollte etwas schief gehen, könnt Ihr es in diesem Fenster immer noch reparieren. Diese Anleitung richtet sich eindeutig an erfahrende Nutzer und ist nichts für Hobbyadmins und „Menschen mit schwachem Herz“.</strong></p>
<p>Server und Client sind bei mir beide Linuxrechner &#8211; für Windows bin ich kein Fachmann. Da aber OpenSSH auch unter Windows arbeitet, dürfte die Konfiguration letzendlich in etwa die gleiche sein.</p>
<p>Alle Einstellungen sind lediglich Vorschläge und nicht verbindlich. Verbesserungen sind natürlich willkommen, eigenes Nachdenken erwünscht. Als Testsystem habe ich <a href="http://www.debian.org/">Debian Squeeze</a> auf dem Server und bei mir zu Hause <a href="https://www.archlinux.de/">ArchLinux</a>. Bei Debian muss der SSH Server aus dem <a href="http://packages.debian.org/unstable/">„unstable“ Zweig</a> installiert werden (libssl, openssh-server, openssh-client), da es dort noch kein aktuelles Paket in testing oder stable gibt. Als Mindestversion empfehle ich OpenSSH 5.8, Version 5.6 sollte aber theoretisch auch funktionieren.</p>
<p>Ich arbeite zunächst als root während der Einrichtung bis ich etwas anderes sage. Wer das nicht möchte, muss überall <code>sudo</code> vor die Befehle schreiben. Sollte noch kein SSH Server und/oder Client installiert sein, fangen wir damit an.</p>
<p><strong>Auf dem Server (root)</strong></p>
<pre class="brush: bash; title: ; notranslate">
apt-get install openssh-server openssh-client libssl
</pre>
<p><strong>Auf dem Client (root)</strong></p>
<pre class="brush: bash; title: ; notranslate">
apt-get install openssh-client
</pre>
<p>Nach kurzer Wartezeit ist unser SSH Server fertig eingerichtet und gestartet.</p>
<h2>Was werden wir tun?</h2>
<ol>
<li>Grundlegende (sichere) Konfiguration des SSH Dienstes</li>
<li>Sperren des SSH Login für root</li>
<li>Anlegen und Einrichten eines neuen Benutzers zum Login</li>
<li>Zugang für diesen Benutzer nur mit gültigem signiertem Schlüssel</li>
</ol>
<h2>Die Konfiguration</h2>
<p>Zunächst sichern wir die aktuelle Konfiguration. Dann editieren wir die sshd_config mit nano (joe, vi usw. gehen natürlich auch).</p>
<p><strong>Auf dem Server (root)</strong></p>
<pre class="brush: bash; title: ; notranslate">
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
nano /etc/ssh/sshd_config
</pre>
<p>Innerhalb der Datei ändere ich die Einstellungen unter dem Punkt <em>Authentification</em> auf die angegebenen Werte. die <em>LoginGraceTime</em> kann auf 10 Sekunden herunter gesetzt werden, da ein Zugriff mit Passwörtern nicht genutzt wird und meine Schlüssel vom <a href="http://en.wikipedia.org/wiki/Ssh-agent">ssh-agent</a> verwaltet werden. Den root Login verbiete ich, denn ich will es „Brute Forcern“ etwas schwerer machen. Die Einstellungen für <em>StrictModes</em>, <em>RSAAuthentication</em>, <em>PubkeyAuthentication</em> bleiben gleich. <em>PasswordAuthentication</em> setze ich hier schon auf no (siehe Hinweise). Wenn Ihr wollt, könnt Ihr auch mit <em>AllowUsers user1 user2</em> usw. eine „Whitelist“ für erlaubte Loginnamen fest legen. Das bietet aber auch nicht mehr Sicherheit &#8211; nur die Fehlermeldung ändert sich.</p>
<p>Die Werte für <em>AuthorizedKeysFile</em>, <em>AuthorizedPrincipalsFile</em> und <em>TrustedUserCAKeys</em> fügen wir hinzu. In der <em>AuthorizedKeysFile</em> stehen normalerweise die Publickeys der Benutzer. Da wir die aber hier nicht brauchen, ändern wir den Wert auf <code>/dev/null</code>. So kann sich kein Benutzer eigene Zugänge hinterlegen. <em>TrustedUserCAKeys</em> ist der öffentliche Teil unseres Zertifikats. In der <em>AuthorizedPrincipalsFile</em> stehen alle Benutzer, die in den Zertifikaten hinterlegt werden. Dazu später noch mehr.</p>
<pre class="brush: plain; title: ; notranslate">
# Authentication:
LoginGraceTime 10
PermitRootLogin no
StrictModes yes
RSAAuthentication yes
PubkeyAuthentication yes

AuthorizedKeysFile /dev/null
TrustedUserCAKeys /etc/ssh/trusted_ca_keys
AuthorizedPrincipalsFile %h/.ssh/authorized_ca_user

PasswordAuthentication no
</pre>
<p>Die Einstellungen übernehmen wir mit einem SSH Neustart. Wenn Ihr Euch nicht sicher seid, wartet noch. Die Änderungen könnt Ihr jederzeit rückgängig machen, indem ihr die .bak Datei zurück kopiert und dann ssh neu startet.</p>
<p><strong>Auf dem Server (root)</strong></p>
<pre class="brush: bash; title: ; notranslate">
/etc/init.d/ssh restart
</pre>
<h2>Der authorisierte Benutzer</h2>
<p>Als nächstes legen wir einen neuen Benutzer an. Den nenne ich jetzt einfach mal login, weil er nur dafür da ist, sich auf dem Server anzumelden. Bevor Ihr versucht anonsphere.com zu brute forcen &#8211; da hab ich nen anderen Benutzer &#8211; ausserdem werde Ihr nach 3 Versuchen gebannt. <img src='http://www.phpgangsta.de/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> Die zweite Zeile ist optional. Ihr könnt natürlich auch ein Passwort für den Benutzer hinterlegen, aber ich habe keine Lust, dass jedesmal einzugeben. Wer sich als dieser Benutzer einloggen kann, könnte eh unbemerkt keylogger o. ä. installieren. Mir persönlich reicht der abgesicherte Zugang. Wenn der Benutzer eingeschränkt handeln soll, also nicht zum root werden darf, ändert den Befehl von -G users,admin auf -g users</p>
<p><strong>Auf dem Server (root)</strong></p>
<pre class="brush: bash; title: ; notranslate">
useradd -c &quot;Login&quot; -d /home/login -G users,admin -u 1003 -m -s /bin/bash login
passwd --delete login
</pre>
<h2>Der normale Schlüssel</h2>
<p>Auf Eurem Clientsystem erzeugen wir für unseren Benutzer einen Schlüssel, falls Ihr schon einen habt, springt zum nächsten <a href="http://www.phpgangsta.de/dieser-schlussel-zerstort-sich-in-30-sekunden-selbst#sig">Kapitel</a>.</p>
<p><strong>Auf dem Client (Benutzer)</strong></p>
<pre class="brush: bash; title: ; notranslate">
ssh-keygen -t rsa -b 4096 -f id_rsa
</pre>
<p>Verschiebt den private Schlüssel in den Ordner ~/.ssh/id_rsa. <strong>Der Publickey wird nicht auf dem Server hinterlegt!</strong></p>
<p><strong>Auf dem Client (Benutzer)</strong></p>
<pre class="brush: bash; title: ; notranslate">
mkdir ~/.ssh/
mv id_rsa ~/.ssh/id_rsa
</pre>
<h2 id="sig">Der signierte Schlüssel</h2>
<p>Zum Erstellen der Zertifikate brauchen wir noch ein Schlüsselpaar. Den Ablauf kennen wir ja schon. Den Inhalt des öffentlichen Schlüssel hinterlegen wir <strong>auf dem Server</strong> in der Datei <em>trusted_ca_keys</em>. Dann wechseln wir auf unseren Benutzer und hinterlegen die ID des Zertifikats („principal“), die erlaubt sein sollen &#8211; dieser muss nicht mit dem Benutzernamen übereinstimmen. Auf dem Server muss nur der Publickey des Zertifikats liegen.</p>
<p><strong>Auf dem Client oder Server (Benutzer)</strong></p>
<pre class="brush: bash; title: ; notranslate">
ssh-keygen -t rsa -b 4096 -f zertifikat_rsa
</pre>
<p><strong>Auf dem Server (root)</strong></p>
<pre class="brush: bash; title: ; notranslate">
cat zertifikat_rsa.pub &gt;&gt; /etc/ssh/trusted_ca_keys
su login
mkdir ~/.ssh/
echo &quot;oliver&quot; &gt;&gt; ~/.ssh/authorized_ca_user
</pre>
<p><strong>Die einzige wichtige Datei ist die <em>zertifikat_rsa</em>. Diese muss gesichert werden (auch mehrfach) und möglichst weit weg von direktem Zugriff (Container, USB Stick, etc.). Alle anderen Dateien sind uninteressant!</strong> Wir haben also jetzt unsere Vorbereitungen getroffen. Als letztes muss noch Euer Publickey (aus „Der normale Schlüssel“) signiert werden. Das macht ihr mit folgender Zeile. I ist der Name der Zertifizierung und steht später im <em>auth.log</em>. <code>n</code> ist der principal, also der Benutzername, für den das Zertifikat ausgestellt ist und der in der <em>authorized_ca_user</em> hinterlegt wurde.</p>
<pre class="brush: bash; title: ; notranslate">
ssh-keygen -s zertifikat_rsa -I MeinLogin -n oliver .ssh/id_rsa.pub
ssh-add .ssh/id_rsa
</pre>
<p>Falls Ihr den SSH Agent benutzt, fügt danach den Schlüssel hinzu mit <code>ssh-add .ssh/id_rsa</code>.</p>
<h2>Aufräumen</h2>
<p>Jetzt könnte es passiert sein, dass die Rechte nicht korrekt gesetzt wurden bei unseren Aktionen. Dieses Problem erledigen wir mit der beliebten „Holzhammermethode“, damit unser Setup sicher ist. Wir gehen zurück auf den root Account auf dem Server und setzen dann unsere Rechte.</p>
<p><strong>Auf dem Server (root)</strong></p>
<pre class="brush: bash; title: ; notranslate">
chown -R root:root /etc/ssh/*
chmod 600 /etc/ssh/*
</pre>
<p><strong>Auf dem Client (Benutzer)</strong></p>
<pre class="brush: bash; title: ; notranslate">
chmod 700 ~/.ssh
chmod 600 ~/.ssh/*
</pre>
<p>Der Login sollte nun funktionieren. Wenn nicht, gibt die Datei <em>/var/log/auth.log</em> (Client und Server) weitere Informationen. Falls da nichts brauchbares steht, erhöht in der <em>ssh_config/sshd_config</em> den <em>LogLevel</em> auf <em>DEBUG3</em>. Fast immer sind irgendwo die Rechte falsch. Wenn bis hier hin alles funktioniert, können wir jetzt ein zeitlich eingeschränktes Zertifikat erzeugen. Dafür benutzen wir diese Zeile.</p>
<p><strong>Auf dem Client (Benutzer)</strong></p>
<pre class="brush: bash; title: ; notranslate">
ssh-keygen -s zertifikat_rsa -I MeinLogin -n oliver -V +5m .ssh/id_rsa.pub
</pre>
<p>Der Zugang wäre damit fünf Minuten gültig. Probiert es aus! Meldet Euch auf dem Server an, meldet Euch ab und schaut, ob Ihr Euch nach 5 Minuten noch anmelden könnt. Wenn Ihr mit dem Prinzip warm geworden seid, könnt Ihr natürlich auch fremde Publickeys signieren. Der Befehl sieht dann z. B. so aus:</p>
<pre class="brush: bash; title: ; notranslate">
ssh-keygen -s zertifikat_rsa -I Zeitarbeiter -n zeitarbeiter -V +1d fremderPubkey.pub
</pre>
<p>Neben der Zeit könnt Ihr auch seine Rechte, wie Port- oder X11-Forwarding einschränken. Mehr Infos bekommt Ihr mit</p>
<pre class="brush: bash; title: ; notranslate">
man ssh-keygen
</pre>
<p>Auf dem Server müsst Ihr dann in der Datei <em>/home/login/authorized_ca_user</em> auf dem Server den Benutzer <em>zeitarbeiter</em> in einer neuen Zeile hinterlegen. Ihr könnt jede ID mehrfach verwenden. So könntet Ihr natürlich auch Signaturen vorher entwerten, indem Ihr einen verwendeten Priincipal löscht. Um einem neuem Benutzer Zugang zu erteilen, benötigt Ihr seinen Publickey. Diesen signiert Ihr mit der <em>zertifikat_rsa</em> und schickt ihm die <em>*-cert.pub</em> Datei zurück. Kein Login nötig!</p>
<h2>Was geht? Was geht nicht?</h2>
<p>Mit Hilfe der Signaturen ist es nun endlich möglich, Zugänge zu Servern zu erteilen, die nach einer gewissen Zeit selbst verfallen, ab einem gewissem Zeitpunkt gültig sind oder Aktionen verbieten, ohne in der sshd_config Änderungen vorzunehmen. Das Verfahren eignet sich u. a. für die Vergabe von Serverzugängen für Wartungsarbeiten an der Datenbank oder zur Einrichtung von Software, die vom Benutzer genutzt wird. Ausserdem natürlich auch für die sichere Vergabe von <a href="http://de.wikipedia.org/wiki/SSH_File_Transfer_Protocol">SFTP</a> oder <a href="http://de.wikipedia.org/wiki/Files_transferred_over_shell_protocol">FISH</a> Zugänge mit denen der Benutzer seine Dateien ändern kann. Wenn jemand für ein Jahr bezahlt und nicht verlängert, haben wir keine Arbeit mehr damit. Verlängert er den Zugang, können wir ihm einfach lokal ein neues Zertifikat generieren.</p>
<p>Der größte Vorteil ist aber, dass Euer Privatekey quasi nicht mehr kompromitiert werden kann. Ich benutze den RSA Schlüssel nur für meine Serverzugänge. Sollte er mir aus irgendwelchen Gründen gestohlen werden und das Passwort gleich dazu, benenne ich einfach den principal um und erzeuge mir ein neues Zertifikat. Meinen Privatekey kann sich derjenige dann ausdrucken und an die Wand hängen, weil der ist für den Zugang völlig unerheblich. Wichtig ist nur die <em>zertifikat_rsa</em>, die muss geschützt werden und diese liegt natürlich sicher in einer verschlüsselten Datei.</p>
<p>Als Einschränkung müssen wir allerdings hin nehmen, dass das Verfahren bisher nur in aktuellen OpenSSH Versionen integriert ist, was evtl. den Zugang durch Programme wie <a href="http://de.wikipedia.org/wiki/Putty">PuTTY</a> oder <a href="http://de.wikipedia.org/wiki/Winscp">WinSCP</a> erschwert. Für Windows habe ich generell noch nach keiner Lösung gesucht. Es kann also sein, dass es schon funktioniert, muss aber nicht &#8211; Infos bitte in die Kommentare. Unter Linux funktioniert das Verfahren mit allen Programmen, die auf der Basis von OpenSSH arbeiten, also eigentlich mit allen.</p>
<p><strong>Einen Hinweis noch</strong><br /> Falls Ihr auf eure Server <a href="http://www.fail2ban.org/wiki/index.php/Main_Page">fail2ban</a> einsetzt, müsst Ihr aus der Filterdatei für ssh die Zeile mit „Invalid Publickey“ entfernen oder auskommentieren, denn der ist durch den Verweis auf /dev/null natürlich immer falsch, auch wenn die Authentifizierung letzendlich erfolgreich ist (und ja, ich hatte beim ersten Mal auch nicht dran gedacht). In diesem Fall solltet Ihr auch eine Whitelist setzen, denn ansonsten werden Benutzer mit falschem Namen nicht immer gebannt.</p>
<p class="wp-flattr-button">
<p><a href="http://www.phpgangsta.de/?flattrss_redirect&amp;id=3156&amp;md5=5c6a4d9193761ed2476c7bebe71d656e" title="Flattr" ><img src="http://www.phpgangsta.de/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phphatesme.com/blog/sicherheit/dieser-schlussel-zerstort-sich-in-30-sekunden-selbst/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Passwort Blacklist</title>
		<link>http://www.phphatesme.com/blog/allgemein/passwort-blacklist/</link>
		<comments>http://www.phphatesme.com/blog/allgemein/passwort-blacklist/#comments</comments>
		<pubDate>Wed, 20 Jul 2011 08:14:36 +0000</pubDate>
		<dc:creator>PHP Gangsta</dc:creator>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[phmnetwork]]></category>
		<category><![CDATA[Sicherheit]]></category>

		<guid isPermaLink="false">http://www.phpgangsta.de/?p=3042</guid>
		<description><![CDATA[Kunden, die eine Webseite mit Registrierung und Login benötigen kann man nicht immer davon überzeugen, strenge Passwortrichtlinien anzusetzen. Wenn ich vorschlage &#8220;10 Zeichen, davon mindestens eine Zahl, ein Großbuchstabe und ein Sonderzeichen&#8221; wird das nicht selten abgelehnt, mit Hinweisen auf &#8220;Dann sinkt die Conversion-Rate&#8221;, &#8220;Dann vergessen die Kunden andauernd ihr Passwort und wir haben mehr [...]]]></description>
			<content:encoded><![CDATA[<p>Kunden, die eine Webseite mit Registrierung und Login benötigen kann man nicht immer davon überzeugen, strenge Passwortrichtlinien anzusetzen. Wenn ich vorschlage &#8220;10 Zeichen, davon mindestens eine Zahl, ein Großbuchstabe und ein Sonderzeichen&#8221; wird das nicht selten abgelehnt, mit Hinweisen auf &#8220;Dann sinkt die Conversion-Rate&#8221;, &#8220;Dann vergessen die Kunden andauernd ihr Passwort und wir haben mehr Supportaufwand&#8221; etc. Also kommt häufig die Richtlinie &#8220;mindestens 8 Zeichen&#8221; zum Einsatz.</p>
<p>Damit ich mich darauf einlasse verlange ich aber mindestens eine Passwort Blacklist, sprich eine Liste der meistgenutzten Passwörter, die dann nicht erlaubt sind, beispielsweise &#8220;12345678&#8243; oder &#8220;passwort&#8221;, um das ganze zumindestens etwas sicherer zu machen. <strong>Man muss den Benutzer vor sich selbst schützen, sonst werden sie &#8220;12345678&#8243; oder &#8220;passwort&#8221; als Passwort nutzen.</strong></p>
<p><span id="more-3042"></span>Gestern ist eine <a href="http://www.heise.de/newsticker/meldung/Rewe-Hinweis-auf-Tauschboersen-Hackerangriff-kam-aus-der-Szene-1281545.html" >Liste mit E-Mail-Adressen und Klartext-Passwörtern von Rewe</a> aufgetaucht, von denen ich die am meisten genutzten Passwörter extrahiert habe. Im Internet findet man auch hier und da &#8220;The Top 50 Passwords&#8221;, da sind aber häufig englischsprachige Begriffe dabei. Mich interessieren bei deutschen Benutzern natürlich deutsche meistgenutzte Begriffe, und da habe ich noch keine längere Liste gefunden mit mehr als 20 Einträgen. Die sortierte Rewe-Liste findet sich übrigens <a href="http://www.phpgangsta.de/download/meistgenutzte_passworte.txt" >hier als Textdatei zum Download</a>. Hier die Top 20:</p>
<pre>123456
sticker
123456789
schmetterling
michael
vanessa
sonnenschein
giraffe
moritz
rewe2011
sabrina
alexander
maximilian
pauline
schule
johanna
elefant
tauschen
dennis
andreas</pre>
<p>Interessant an dieser Liste ist, dass &#8220;passwort&#8221; erst weit unten erscheint, in englischen Listen ist &#8220;password&#8221; eigentlich immer in den Top3.</p>
<p>Microsoft hat letzte Woche groß angekündigt dass <a href="http://www.heise.de/security/meldung/Hotmail-Gehackte-Accounts-von-Kontakten-melden-1280009.html" >Hotmail-Nutzer nun keine leichten Passwörter wie &#8220;123456&#8243; mehr benutzen können</a>, sprich sie haben auch eine Blacklist geschaltet. Dass man für solch eine Selbstverständlichkeit, die man hätte schon vor Jahren aktivieren müssen, eine große Pressemitteilung verbreiten kann ist mir ein Rätsel.</p>
<p>Nutzt ihr auch Passwort Blacklists? Wie sieht eure Sperrliste aus? Mich würden vor allem deutsche Passwörter interessieren die häufig genutzt werden und die man sperren sollte.</p>
<p class="wp-flattr-button">
<p><a href="http://www.phpgangsta.de/?flattrss_redirect&amp;id=3042&amp;md5=b688e286bc308d9bfa60a8294dee1ea3" title="Flattr" ><img src="http://www.phpgangsta.de/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phphatesme.com/blog/allgemein/passwort-blacklist/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Schöner hashen mit bcrypt</title>
		<link>http://www.phphatesme.com/blog/sicherheit/schoner-hashen-mit-bcrypt/</link>
		<comments>http://www.phphatesme.com/blog/sicherheit/schoner-hashen-mit-bcrypt/#comments</comments>
		<pubDate>Mon, 18 Jul 2011 06:56:09 +0000</pubDate>
		<dc:creator>Oliver Klee</dc:creator>
				<category><![CDATA[phmnetwork]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Sicherheit]]></category>

		<guid isPermaLink="false">http://www.phpgangsta.de/?p=2946</guid>
		<description><![CDATA[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ängisten Internetsprachen: PHP, HTML, Javascript und CSS. Bei meinem vorherigem Gastbeitrag wurde ich direkt im ersten Kommentar aus meiner heilen [...]]]></description>
			<content:encoded><![CDATA[<p><em>Gastartikel von Oliver Sperke.</em></p>
<p><em>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ängisten Internetsprachen: PHP, HTML, Javascript und CSS.</em></p>
<p>Bei meinem <a href="http://www.phpgangsta.de/passwortmythen-oder-%e2%80%9ewas-du-schon-immer-uber-passworter-wusstest-aber-nie-zu-sagen-wagtest%e2%80%9c">vorherigem Gastbeitrag</a> wurde ich direkt im ersten Kommentar aus meiner heilen Welt geworfen. Dort stand nämlich folgender „erschütternder Kommentar“ zu lesen:</p>
<blockquote><p>Das du Salting und Mehrfachhashing predigst, während der Rest der Welt schon einen Schritt weiter zu bcrypt geht… Traurig.</p>
</blockquote>
<p>Nun ja, dazu möchte ich drei Dinge sagen.</p>
<ol>
<li>Ich predige nicht (Ausnahme: „Es heißt Standard, verdammt, nicht <a href="http://www.google.de/?q=standart">Standart</a>!“).</li>
<li>Ach, wenn die Welt schon mal auf dem Stand des einfachen md5 wäre &#8230;</li>
<li>Bcrypt verdient einen eigenen Beitrag.</li>
</ol>
<p>Natürlich hatte der Autor völlig recht. Über Hashfunktionen im Web zu schreiben und bcrypt nicht zu erwähnen ist fast schon schändlich. Also <a href="http://www.usenix.org/events/usenix99/provos.html">bcrypt</a> ist eine Hashfunktion, die auf Langsamkeit optimiert wurde. Um genauer zu sein, es ist nicht mal ein richtiger Hashalgorithmus, sondern eine Blowfish Verschlüsselung, bei der am Ende „die Schlüssel weggeworfen werden“, daher lässt sich das Ergebnis nicht mehr entschlüsseln. bcrypt ist eine Weiterentwicklung der „<a href="http://en.wikipedia.org/wiki/Crypt_%28Unix%29#Traditional_DES-based_scheme">Traditional DES Scheme</a>“ Funktion aus der Unixwelt. Obwohl dieses Verfahren 30 Jahre lang (!) gute Dienste geleistet hat, stellen sich so langsam „Alterserscheinungen“ ein. Der Zahn der Zeit nagt auch hier in Form von gestiegener Rechenleistung.</p>
<h2>Kurze Rückschau</h2>
<p><span id="more-2946"></span>Hashalgorithmen wie md5 und die shaX sind auf Schnelligkeit optimiert. Das ist gut, wenn man prüfen will, ob der heruntergeladen Film auch wirklich korrekt übertragen wurde. Das ist auch gut, wenn man testen möchte, ob das SSL Zertifikat einer Webseite nicht verfälscht wurde. Das ist aber eher suboptimal, wenn man damit Passwörter speichern will. Wie schon im letzten Artikel erklärt und <a href="http://www.phpgangsta.de/passwortmythen-oder-%e2%80%9ewas-du-schon-immer-uber-passworter-wusstest-aber-nie-zu-sagen-wagtest%e2%80%9c#comments">ausgiebig diskutiert</a>, ist die gestiegene Rechenleistung auch ein Problem für die klassischen Hashfunktionen in Webanwendungen. Zwar kann man mit Salts, mehr Salts und Mehrfachhashes das Schlimmste verhindern, aber irgendwie ist das <a href="http://www.klamm.de/forum/f28/php-mysql-passwoerter-richtig-verschluesseln-251427.html">alles nicht so nachvollziehbar für jeden</a>. Kurz gesagt: „Das geht besser“.</p>
<h2>Was bcrypt kann</h2>
<p>Selbst wenn wir dafür sorgen, dass unsere Passwörter gut geschützt sind, können wir natürlich kaum verhindern, dass ein Benutzer trotzdem ein schwaches Passwort verwendet. Wenn es der Angreifer gezielt auf eine Person, z. B. den Admin abgesehen hat, wird die Situation noch schlimmer, denn bis <a href="http://www.phpgangsta.de/passwortmythen-oder-%e2%80%9ewas-du-schon-immer-uber-passworter-wusstest-aber-nie-zu-sagen-wagtest%e2%80%9c">10 Zeichen</a> kann man auch schon mal eine Brute Force Attacke für einen einzelnen Hash probieren. Deshalb sollten wir unserem <a href="http://de.wikipedia.org/wiki/Cracker_%28Computersicherheit%29">Cracker</a> das Leben grundsätzlich so schwer wie möglich machen.</p>
<p>Bcrypt bringt gewisse Vorkehrungen für genau diesen Fall mit. Der Algorithmus ist auch optimiert noch sehr langsam, und das ist gut so. Der Hash beinhaltet einen Wert für die Rundenanzahl, den sog. „Kostenfaktor“. Dies ist der Aufwand der bei der Berechnung betrieben werden muss. Jedem Hash kann zusätzlich ein individueller Salt zugeordnet werden. In PHP ist bcrypt über die <a href="http://de.php.net/manual/de/function.crypt.php">crypt()</a> Funktion seit Version 5.3 fest implementiert. Davor hing der Einsatz vom Betriebsystem ab.</p>
<h2>Was bcrypt nicht kann</h2>
<p>Bcrypt bringt einige schöne Fähigkeiten mit, die wir in der Webwelt wunderbar nutzen können. Allerdings gibt es einige Dinge, die designbedingt nicht vorgesehen sind. Dazu zählt ein geheimer Salt, den wir in unserer Anwendung hinterlegen können. Der Sinn resultiert aus der Überlegung, dass wenn ein Angreifer aus welchen Gründen auch immer auf die Datenbank zugreifen kann, er auch noch auf den Quelltext der Webanwendung zugreifen können muss. Im Zweifel entscheidet sich dort, ob unsere Passwörter weiter geschützt sind oder nicht.</p>
<p>Die zweite fehlende Funktion, ist die Möglichkeit Hashes von zusätzlichen Faktoren, wie der E-Mail Adresse (ersatzweise dem Benutzernamen oder die UserID) abhängig zu machen. Der Hintergrund ist etwas speziell. Nehmen wir mal an, ein Angreifer findet in unserer Webanwendung eine <a href="http://de.wikipedia.org/wiki/Cross-Site_Scripting">XSS Lücke</a>, mit denen er die Session eines Benutzers übernehmen kann. Was wäre das Schlimmste, was er tun kann? Richtig, er ändert das Passwort oder die E-Mail Adresse. Wie kann ich das am effektivsten verhindern? Ganz klar, ich muss ihn zwingen zur Überprüfung das alte Passwort einzugeben. Durch die Kopplung der Hashes an die E-Mail kann ich das gar nicht vergessen. Man könnte natürlich den Salt abhängig von der E-Mail machen, aber was ist wenn ein Benutzer mehrfach angemeldet ist? Brute Force Attacken werden mit jedem Ziel lohnenswerter.</p>
<h2>Vom Rein und Raus</h2>
<p>Ein ganz einfacher Hash ensteht so:</p>
<pre class="brush: php; title: ; notranslate">crypt ( 'Passwort', '$2a$04$EinSaltFuerDasPasswort' );</pre>
<p>Als Ausgabe ergibt sich:</p>
<pre>$2a$04$EinSaltFuerDasPasswore.oNHNUzZrs1V5tpdv/WJ64.DIyBV1kC</pre>
<p>Auf den ersten Blick ist das im Vergleich zu md5(&#8216;Passwort&#8217;) natürlich etwas verwirrend, aber dafür schreibe ich das ja hier. Im ersten Argument steht der zu hashende String. Das zweite Argument besteht aus drei Teilen, die je mit einem $ eingeleitet werden. Der erste Block bestimmt die verwendete Funktion. Die möglichen Werte könnt Ihr auf php.net nachschauen. Wir nutzen hier nur $2a für bcrypt.</p>
<p>Der zweite Block beschreibt die Anzahl der Runden, mit dem der Hash erstellt wird. Der Wert darf zwischen 04 und 31 liegen. Mit jeder Runde verdoppelt sich die Zeit zur Erstellung, das System ist also exponentiell. Wenn eine Runde etwa 1 ms dauert, dann dauern 31 Runden ca. 74 Minuten. Genug Luft nach oben also. Brauchbare Werte liegen derzeit bei etwa 08 bis 12, je nach eingesetzter Hardware und Geduld. Gibt man Zahlen ausserhalb des Bereichs an, wird *0 zurück gegeben.</p>
<p>Der dritte Block ist der individuelle Salt. Dieser darf aus Groß- und Kleinbuchstaben, Zahlen, sowie ./ bestehen. Tauchen andere Zeichen auf, wird ebenfalls *0 zurück gegeben. Die Eingabewerte müssen also gut gewählt sein. Weiterhin darf der Salt aus 128 Bits, also 21 1/2 Zeichen bestehen. Wen das verwundert, 21 Zeichen werden komplett dargestellt, beim letzten Zeichen werden die Hälfte der Bits verworfen. Deshalb wird aus &#8216;EinSaltFuerDasPasswort&#8217; im hash &#8216;EinSaltFuerDasPasswore&#8217;.</p>
<p>Die Ausgabe entspricht der Eingabe, gefolgt vom eigentlichem Hash. Jetzt kann man natürlich berechtigt fragen, was daran sicher sein soll, wenn da ja alles steht. Stimmt, aber genau dieses Verfahren ist gleichzeitig ein Vorteil.</p>
<h2>Einmal bcrypt &#8230;</h2>
<p>Ich erstelle der Einfachheit halber eine Funktion, mit der man die Eigenschaften von bcrypt richtig nutzen kann. Auch hier gilt wieder &#8211; nichts ist in Stein gemeisselt. Wenn Ihr Vorschläge habt, her damit. Die Funktionen nenne ich (besonders kreativ) bcrypt_encode und bcrypt_check.</p>
<pre class="brush: php; title: ; notranslate">function bcrypt_encode ( $password )
{
	return crypt ( $password, '$2a$04$EinSaltFuerDasPasswort' );
}</pre>
<p>Diese Funktion gibt uns einen ersten Anfang. Ein Aufruf von bcrypt(&#8216;Passwort&#8217;) gibt uns den o. g. Hash zurück. Die Saltfunktion nutzt natürlich überhaupt nichts, wenn man überall den gleichen Salt verwendet. Da der Salt in der Datenbank steht und daher nicht geheim ist, kann dieser <a href="http://de.wikipedia.org/wiki/Pseudozufall">pseudozufällig</a> sein kann. Folgendes Konstrukt ist also ausreichend.</p>
<pre class="brush: php; title: ; notranslate">$salt = substr ( str_shuffle ( './0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' ) , 0, 22 );</pre>
<p>Die Anzahl der Runden sollte variabel sein. Der Hintergrund ist ganz einfach. Manche Accounts sind wichtiger als andere. Wenn ich als Admin 3 Sekunden zum Login warten muss, dann stört mich das nicht. Einem Besucher diese Wartezeit zu erklären, könnte sich aber schwierig gestalten oder als technische Schwäche fehlinterpretiert werden. Als Bonbon kann man dem Besucher auch anbieten, die sichere Variante zu wählen. Ein Normalwert sollte festgelegt werden, aber mit der Möglichkeit zu abweichenden Werten. Übertragen auf unsere Funktion ergibt sich.</p>
<pre class="brush: php; title: ; notranslate">function bcrypt_encode( $password, $rounds='08' )
{
	$salt = substr ( str_shuffle ( './0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' ) , 0, 22 );
	return crypt ( $password, '$2a$' . $rounds . '$' . $salt );
}</pre>
<p>Zur Passwortspeicherung habe ich jetzt eigentlich alle Möglichkeiten von bcrypt ausgeschöpft. Mit jedem Aufruf wird ein neuer Hash mit einem anderem Salt erzeugt. Nur sicherer fühl ich mich jetzt nicht, denn genau wie oben schon erwähnt gebe ich dem Angreifer freiwillig alle Daten. Es ist natürlich besser als ein purer md5 hash, aber eher noch gut gemeint als gut gemacht.</p>
<p>Daher würde ich diese Funktion gerne erweitern. Wie bei unserem md5 Beispiel bringe ich zusätzlich einen Salt ein, der nur im Quelltext hinterlegt ist. Dieser muss vor dem ersten Aufruf der Funktion mit define(&#8216;SALT&#8217;, &#8216;beliebigerWert&#8217;) definiert werden. Ausserdem möchte ich, dass man bei einer Änderung der E-Mail Adresse das alte Passwort eingeben werden muss. In den Kommentaren zum letzten Beitrag hat ein Besucher <a href="http://www.phpgangsta.de/passwortmythen-oder-%E2%80%9Ewas-du-schon-immer-uber-passworter-wusstest-aber-nie-zu-sagen-wagtest%E2%80%9C#comment-19723">erwähnt</a>, dass das Einbringen eines Salt mit hash_hmac() sicherer wäre als einfaches voranstellen oder anhängen. Auch wenn ich die Bedenken in diesem speziellem Fall nur bedingt teile, da sich der individuelle Salt in jeder Zeile ändert und daher ein Angriff auf den systemweiten Salt sinnlos wäre, schaden kann es auch nicht und wenn wir schon einmal dran sind, klotzen wir mal richtig. <img src='http://www.phpgangsta.de/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>Dazu erweitern wir zunächst einmal mit <a href="http://de.php.net/manual/de/function.str-pad.php">str_pad()</a> unseren String auf die viefachefache Länge des Passwortes, indem wir ihn mit dem sha1 hash der E-Mail Adresse davor und dahinter auffüllen. Ich nehme hier sha1, weil ich möchte, dass sich bei jeder E-Mail der Salt komplett ändert. Diesen String jagen wir dann durch <a href="http://de.php.net/manual/de/function.hash-hmac.php">hash_hmac()</a> mit unserem systemweiten Salt <a href="http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html">in Whirlpool</a> als Binärausgabe. Den entstandenen Zeichensalat verpacken wir mit bcrypt.</p>
<pre class="brush: php; title: ; notranslate">function bcrypt_encode ( $email, $password, $rounds='08' )
{
	$string = hash_hmac ( &quot;whirlpool&quot;, str_pad ( $password, strlen ( $password ) * 4, sha1 ( $email ), STR_PAD_BOTH ), SALT, true );
	$salt = substr ( str_shuffle ( './0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' ) , 0, 22 );
	return crypt ( $string, '$2a$' . $rounds . '$' . $salt );
}</pre>
<p>Ein Aufruf von</p>
<pre class="brush: php; title: ; notranslate">bcrypt_encode( 'oliver@anonsphere.com', 'Test-Null8Fünfzehn' );</pre>
<p>führt also zu diesen Ergebnissen:</p>
<pre class="brush: php; title: ; notranslate">// Passwort mit E-Mail auf vierfache Länge aufgefüllt
4e707693b984367edadf5a022867Test-Null8Fünfzehn4e707693b984367edadf5a022867e

// hash_hmac mit Whirlpool und systemweitem Salt (im Original binär)
b0492febbd81ef10387e2e7127295e09c197ff0cadf8ae5dc98182178f9e0891cf86b91abb1c723e0de510361cb67e1149460a687271672d77de439d7c572b57

// Verpackt mit bcrypt
$2a$08$jb8v67zmCNMO9dlX1tkVqOxGlhQkJNL45AvfpbEWvqXnGC8YcO7Hm</pre>
<p>Die Sicherheit dürfte nur schwer anzuzweifeln sein. <img src='http://www.phpgangsta.de/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<h2>&#8230; und zurück</h2>
<p>Jetzt fehlt noch die Möglichkeit den gespeicherten Passworthash mit unserem Passwort zu vergleichen. Jetzt kommen wir zu dem Teil, wo bcrypt von nett, auf cool wechselt.<br />
<code></code></p>
<pre>$2a$08$jb8v67zmCNMO9dlX1tkVqOxGlhQkJNL45AvfpbEWvqXnGC8YcO7Hm</pre>
<p><code></code><br />
Schauen wir uns doch mal diesen Hash genauer an. Wir haben oben gesehen, der Hash besteht aus den Einstellungen und dem Ergebnis. Anders gesagt, der Hash liefert uns alles, was wir zum Berechnen brauchen. Dazu schreibe ich ihn mal anders, damit es klarer wird.<br />
<code></code></p>
<pre>Einstellungen: $2a$08$jb8v67zmCNMO9dlX1tkVqOx
         Hash: GlhQkJNL45AvfpbEWvqXnGC8YcO7Hm</pre>
<p><code></code><br />
Der erste Teil entspricht genau dem Code, den wir zur Erzeugung genutzt haben, daher muss auch bei korrekter E-Mail und Passwort und diesen Einstellungen unser Hash heraus kommen. Dass heißt, wenn der hinterlegte hash die Variable $stored hat, dann muss folgende Bedingung wahr sein.</p>
<pre class="brush: php; title: ; notranslate">crypt ( $string, substr ( $stored, 0, 30 ) ) == $stored;</pre>
<p>Oder übertragen in eine eigene Funktion.</p>
<pre class="brush: php; title: ; notranslate">function bcrypt_check ( $email, $password, $stored )
{
	$string = hash_hmac ( &quot;whirlpool&quot;, str_pad ( $password, strlen ( $password ) * 4, sha1 ( $email ), STR_PAD_BOTH ), SALT, true );
	return crypt ( $string, substr ( $stored, 0, 30 ) ) == $stored;
}</pre>
<p>Der Vorteil erschliesst sich erst auf den zweiten Blick. Während man bei der Umstellung von md5 auf sha1 oder von sha1 auf sha256 Probleme mit bestehenden Benutzerlogins bekommt, weil die alten Passwörter ungültig werden, nimmt uns bcrypt alle nötigen Workarounds ab. Bei der Prüfung ist es nämlich vollkommen egal, was als Ursprungswert an Runden und Salt hinterlegt wurde. Wenn ich irgendwann mal die Sicherheit erhöhen will oder auf einen schnelleren/langsameren Server umziehe, ändere ich den $rounds Wert und trotzdem funktionieren alte Logins weiter. Sobald aber die E-Mail oder das Passwort geändert wird, wird der neue Wert übernommen.</p>
<h2>Was noch zu sagen wäre</h2>
<p>Bcrypt ist eine schöne Sache, entbindet Euch aber keineswegs von zusätzlichen Sicherheitsüberlegungen. Wer zukunftsorientiert an ein neues Projekt geht oder wer schon beim letzten Artikel überlegt hat, ob seine Passwortspeicherung wirklich so sicher ist, wie er dachte, sollte überlegen, ob der Einsatz lohnt. Ein sicheres Verfahren deshalb abzulösen, ist aber auf jeden Fall unnötig.</p>
<p>Bleibt mir abschliessend nur noch <a href="http://www.gernothassknecht.de/">eins zu sagen</a>: „ES HEISST STANDARD!!11“.</p>
<p class="wp-flattr-button">
<p><a href="http://www.phpgangsta.de/?flattrss_redirect&amp;id=2946&amp;md5=17694ac7d39c8a04050dd5dac06c9043" title="Flattr" ><img src="http://www.phpgangsta.de/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phphatesme.com/blog/sicherheit/schoner-hashen-mit-bcrypt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

