WordPress: wichtige Sicherheitsmaßnahmen

Wer WordPress nutzt, wird sich schon Gedanken darüber gemacht haben, wie man die Sicherheit des Systems erhöhen kann. WordPress hat ein eigenes Security Team, welches die Software stetig auf Schwachstellen hin überprüft, daher gilt der Core auch als recht sicher. Allerdings gibt es auch hier ständig neue potentielle Sicherheitslücken, wie beispielsweise die neue Rest-API. Größter Angriffsvektor für Hacker bleiben jedoch nach wie vor schlampig programmierte WordPress-Plugins. Wer die Full Disclosure-Mailingliste abonniert hat, wird wissen, was ich meine: Dort tauchen ziemlich regelmäßig Schwachstellen in WordPress-Plugins auf. Wie kann man sich nun aber effektiv schützen, auch wenn man auf bestimmte Plugins angewiesen ist? Dieser Post soll eine lose Sammlung effizienter Maßnahmen sein, die die Sicherheit des Systems verbessern.

Keine Ausführungsrechte für das DocumentRoot

Letztens hat mir jemand eine WordPress-Instanz über ein anfälliges WordPress-Plugin gehackt, eine PHP-Shell hingelegt und darüber NodeJS heruntergeladen. Anschließend wurden verschiedene Hacks auf weitere Seiten aufgeführt. Wie kann man das verhindern? Unter Linux gibt es die Möglichkeit, beim Mounten von Filesystemen die Option noexec zu setzen. Diese gewirkt, dass grundsätzlich ausführbare Dateien (wie Binaries oder Skripte) nicht ausgeführt werden können. Die Option kann man einfach in der /etc/fstab mitgeben. Voraussetzung ist natürlich, dass das DocumentRoot auf einem eigenen Filesystem liegt, beispielsweise auf einem LVM-Volume. Ist das nicht so, kann man sich mit einem kleinen Trick behelfen. Im Beispiel ist /var/www/html das DocumentRoot:

$ mount -o bind /var/www/html /var/www/html
$ mount -o remount,noexec /var/www/html

Der erste Befehl mountet das Verzeichnis auf sich selbst als sogenannten Bind-Mount. Der zweite Befehl setzt für den Mount die Option noexec und verhindert damit das Ausführen von Dateien. Folgendermaßen kann das getestet werden:

$ cat <<EOF > /var/www/html/test.sh
> #!/bin/bash
> echo "Hello World"
> EOF
$ chmod 755 /var/www/html/test.sh
$ /var/www/html/test.sh
bash: /var/www/html/test.sh: Keine Berechtigung

weiterlesen

Apache 2.4 mit PHP5 FPM via Sockets

Vorwort

Die meisten Anleitungen für einen Apache2 mit PHP lassen den User PHP als Apache-Modul installieren. Das hat der Vorteil, dass es extrem einfach zu installieren ist und keinen weiteren Konfigurationsaufwand braucht. Für Webserver, auf denen nur eine Site läuft, ist das oft auch ausreichend. Sobald aber mehr als eine Site betrieben wird, muss man sich darüber Gedanken machen, dass PHP immer unter dem Webserver-Nutzer (per default www-data) läuft. Eine Implikation daraus ist, dass wenn eine Site erfolgreich gehackt wird, der Angreifer auch Zugriff auf die andere Site hat, und auch auf alle Inhalte, die der Nutzer www-data lesen darf. Das ist sicherheitstechnisch bedenklich. Nun gibt es verschiedene Möglichkeiten dieses Problem zu lösen. Eines wäre PHP via SuExec und FastCGI anzusprechen. Das ist hier im Hetzner-Wiki erklärt. Eine andere Lösung ist PHP FPM (FastCGI Process Manager) zu nutzen. Das soll hier erklärt werden.

Installation

Ein funktionierender Apache wird vorausgesetzt. Fall noch nicht installiert braucht man noch das FastCGI-Modul. Außerdem brauchen wir auch PHP-FPM.

$ apt-get install libapache2-mod-fcgid php5-fpm
$ a2enmod proxy_fcgid
$ apache2ctl configtest && apache2ctl graceful

Damit ist das FastCGI-Proxy-Modul installiert und aktiviert. PHP-FPM sollte fehlende Abhängigkeiten ebenfalls mit installiert haben.

Konfiguration

PHP-FPM Konfiguration

Die grundsätzliche Konfiguration von PHP-FPM wird in /etc/php5/fpm/php-fpm.ini gemacht. Dort kann man reinschauen, muss aber meist nichts ändern. Wichtig sind die sogenannten Pool-Konfigurationen. Diese liegen unter /etc/php5/fpm/pool.d. Eine Default-Konfiguration liegt schon dort (www.conf), allerdings sollte diese nur zu Referenzzwecken verwendet werden. Um diesen Pool zu deaktivieren kann man ihn einfach umbenennen:

mv /etc/php5/fpm/pool.d/www.conf /etc/php5/fpm/pool.d/www.conf_inactive

Eine neue Pool-Konfiguration hingegen könnte beispielsweise so aussehen:

[cloud]
user = www-user-cloud
group = www-user-cloud
listen = /var/run/php5-fpm-cloud.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 256
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
;pm.status_path = /status
;ping.path = /ping
access.log = "/var/www/sites/cloud.misterunknown.de/logs/php-$pool.access.log"
access.log = "/var/www/sites/cloud.misterunknown.de/logs/php-$pool.access.log"
access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
slowlog = "/var/www/sites/cloud.misterunknown.de/logs/php-$pool.slow.log"
security.limit_extensions = .php .php3 .php4 .php5

php_flag[display_errors] = off

php_admin_flag[log_errors] = on

php_admin_value[max_execution_time] = 600
php_admin_value[error_reporting] = E_ALL
php_admin_value[open_basedir] = "/var/www/sites/cloud.misterunknown.de:/var/www/sites/cloud.misterunknown.de/tmp:/data/owncloud:/dev/urandom"

weiterlesen

Roundcube: Ausgehende IP festlegen

Wer mittels Roundcube Mails direkt an einen entfernten (nicht lokalen) Mailserver sendet, möchte unter Umständen die ausgehende IP festlegen, um beispielsweise sicherzustellen, dass der Reverse-DNS-Eintrag korrekt ist. Direkt in Roundcube gibt es dafür keine Einstellung, aber über die Stream-Kontext-Optionen von PHP kann man das festlegen.

weiterlesen

Javascript: Einfache AJAX-Demo

Das ist eine einfache AJAX Demonstration. In das untenstehende Suchfeld können Eingaben gemacht werden. Von einem eigens dafür geschriebenen PHP-Skript wird dann das übergebene POST-Array zurückgegeben und vom Request-Skript in den Ergebnis-Div geschrieben.

Geben Sie einfach etwas in das Eingabefeld ein und im Ergebnis-Div erscheint die Rückmeldung.

Ergebnis:

Code zum Beispiel

Der Quellcode zum Beispiel sieht recht komplex aus, ist aber relativ einfach verständlich. Im HTML gibt es ein Input-Feld welches mittels des Attributs onkeyup=“searchFor(this.value)“ einen Eventhandler zugewiesen bekommt. Die Javascript-Funktion sieht folgendermaßen aus.

function searchFor(suchbegriff){
	var xmlHttp = null; // unser Request-Objekt
	// Mozilla, Opera, Safari sowie Internet Explorer 7
	if (typeof XMLHttpRequest != 'undefined') {
		xmlHttp = new XMLHttpRequest();
	}
	if (!xmlHttp) {
		// Internet Explorer 6 und älter
		try {
			xmlHttp  = new ActiveXObject("Msxml2.XMLHTTP");
		} catch(e) {
			try {
				xmlHttp  = new ActiveXObject("Microsoft.XMLHTTP");
			} catch(e) {
				xmlHttp  = null;
			}
		}
	}
	// Wurde das Objekt korrekt erzeugt?
	if (xmlHttp) {
		// Woher wollen wir Daten haben?
		var url = "http://api.misterunknown.de/selfhtml/ajaxdemo.php";
		// Wir wollen auch Parameter übergeben
		var params = "suchbegriff="+suchbegriff;
		// Wir senden die Daten mittels eines POST-Requests
		xmlHttp.open("POST", url, true);
		// Headerinformationen für den POST Request
		xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		xmlHttp.setRequestHeader("Content-length", params.length);
		xmlHttp.setRequestHeader("Connection", "close");
		// Was soll passieren, wenn wir die Daten haben? Natürlich wollen wir sie ausgeben
		xmlHttp.onreadystatechange = function () {
			// prüfen, ob das Ergebnis korrekt geliefert wurde
			if (xmlHttp.readyState == 4) {
				// Zurückgeliefertes Ergebnis wird in den DIV "ergebnis" geschrieben
				document.getElementById("ergebnis").innerHTML = xmlHttp.responseText;
			}
		};
		// und weg damit 😉
		xmlHttp.send(params);
	}
}

weiterlesen

IFM: improved file manager

Seit einigen Tagen habe ich an einem neuen Dateimanager für meinen Webspace gearbeitet, und jetzt steht die erste Alpha-Version, die erst noch umfangreich getestet werden muss, aber schon recht ordentlich läuft, zur Verfügung (https://github.com/misterunknown/ifm). Er basiert auf meinem EPFM (Easy PHP File Manager), ist aber etwas größer und funktioniert wie ein Client-Server-System, wobei es dennoch eine single-file-Lösung geblieben ist.
Beim Aufrufen des Skripts wird ein dynamisches Interface gesendet, welches mit HTML5, CSS3 und Javascript umgesetzt ist; im Hintergrund arbeitet das Skript mit einem PHP-API, welches mit dem Interface über JSON kommuniziert. Damit minimiert man den Traffic den das Skript generiert, da im Gegensatz zum EPFM nicht jedes mal das ganze Markup mitgesendet wird, sondern nur relevante Teile per AJAX geladen werden. Das verwendete jQuery ist im Skript integriert, was die etwas üppigere Dateigröße ausmacht.

weiterlesen

Easy PHP File Manager

Der Easy PHP File Manager ist in Version 2.2.7 erschienen. Die single file Lösung hatte sich auf meinen Servern schon sehr etabliert und verlangte nach einigen Verbesserungen.
Es können jetzt auch Benutzer und Gruppe einer Datei oder eines Verzeichnisses angezeigt werden, außerdem ist Emmet jetzt direkt integriert. Verschiedene Informationen, wie Dokumentation, vollständige Funktionsliste, Installationsanleitung etc. gibt es auf der neuen Internetpräsenz des EPFM.

weiterlesen