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

WordPress: Automatischen Anker (ID-Attribut) für Überschriften einfügen

Auf Webseiten mit viel Inhalt, wie beispielsweise Wiki-Seiten oder Dokumentationen, gibt es die Möglichkeit Anker an bestimmten Stellen zu setzen, die man mit Links referenzieren kann. Das ist einerseits mit benamten Link-Tags möglich, andererseits mit IDs.

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

Owncloud zu Nextcloud migrieren

Nach Unstimmigkeiten des Owncloud-Gründers mit der dahinter stehenden Firma hat er einen eigenen Fork namens Nextcloud erstellt. Im Nachgang musste die amerikanische Firma Owncloud Inc. schließen, nachdem ihnen die Kreditlinie gestrichen wurde. Die Owncloud GmbH in Deutschland ist davon zwar nicht unmittelbar betroffen, es bleibt aber wohl eine Frage der Zeit.

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

OXID esales: mod_rewrite wird als nicht aktiv angezeigt

tl;dr: Problem war der .htaccess-Verzeichnisschutz, der verhindert, dass OXID korrekt prüfen kann, ob mod_rewrite funktioniert. Die Lösung ist den Schutz zu deaktivieren oder die Server-IP explizit zuzulassen.

Ich habe kürzlich einen OXID esales Shop installiert. An sich ist das kein Hexenwerk, allerdings gab es ein hartnäckiges Problem: mod_rewrite wurde nicht erkannt bzw. als nicht aktiv markiert. In diversen Foren liest man nur, dass man einfach im Code (!) die Prüfung deaktivieren könne. Da es mir eigentlich fern liegt, als „Laie“ an fremdem Code zu frickeln, daher habe ich das Problem mal nachvollzogen.

Der OXID-Shop überprüft das Vorhandensein von mod_rewrite auf recht kreative Art und Weise. Der zugehörige Code steht in core/oxsysrequirements.php (ctrl+f checkModRewrite) Und zwar wird folgender Request an den Server gesendet:

http://&lt;domain&gt;/oxseo.php?mod_rewrite_module_is=off

Durch eine RewriteRule, die in der mitgelieferten .htaccess-Datei steht, wird der Request aber umgeschrieben:

RewriteCond %{REQUEST_URI} oxseo\.php$
RewriteCond %{QUERY_STRING} mod_rewrite_module_is=off
RewriteRule oxseo\.php$ oxseo.php?mod_rewrite_module_is=on [L]

Das aufgerufene Skript macht dabei nichts anderes als zu prüfen, wie der übergebene Parameter lautet (also ob korrekt umgeschrieben wurde) und anschließend entweder mod_rewrite_on oder mod_rewrite_off auszugeben.

Per Hand abgesetzt brachte der Request aber die korrekte Ausgabe. Der Fehler lag also irgendwo in der Kommunikation und war schnell gefunden: Ich hatte für das Aufsetzen eine Authentifizierung per .htaccess eingerichtet. Diese funkte jetzt dazwischen und beantwortete den Request von OXID mit einem 401. Da das dort nicht abgefangen wird, geht der Shop davon aus, dass mod_rewrite nicht korrekt arbeitet. Die Lösung sah einfach aus: Zusätzlich zu der Authentifizierung per Username und Passwort darf auch der Server selbst auf sich zugreifen:

Require group oxid
Require ip &lt;IP des Servers&gt;

weiterlesen

Cleveres Webmail: Rainloop

Freie Webmail Software gibt es einige: Squirrelmail und Roundcube sind dabei die bekanntesten. Nachdem ich mehrere Jahre Roundcube genutzt habe, probiere ich gerade Rainloop aus.

Features

Grundsätzlich bietet Rainloop IMAP und SMTP Support jeweils einschließtlich SSL und STARTTLS. Außerdem gibt es ein Plugin-System, welches dem Nutzer erlaubt, die Software um sinnvolle Funktionen ergänzen. Eine Liste von Features gibt es hier. Am liebsten sind mir aber die Tastenkürzel, die sowohl eine schnelle Navigation durch die Nachrichten als auch einige Aktionen, wie beispielsweise das Verschieben von Mails in einen anderen Ordner erleichtern. Für Maus-Muffel, wie ich als Linux-Admin einer bin, ist das wie geschaffen.

weiterlesen

WordPress: Rich Snippet Tester bringt „missing required field updated“

Ich habe kürzlich meinen Blog mit entsprechenden Autor-Informationen ausgestattet, um in den Google-Suchergebnissen mit Bild und Namen aufzutauchen. Wer weiß, vielleicht spielt das ja irgendwann mal irgendeine Rolle^^ Man kann nie wissen.

Fakt ist, dass ich, um zu testen ob es funktioniert, das sogenannte „Test-Tool für strukturierte Daten“ ausprobiert habe (engl. rich snippet test). Soweit war da auch alles ok, nur ein Feld hat gefehlt und zwar „updated“. Ein kurzes Googleln brachte die Erkenntnis, dass Google ein Feld erwartet in dem steht, wann der entsprechende Beitrag das letzte mal geändert wurde. Möchte man einfach nur diesen ärgerlichen Fehler beseitigen, kann man einfach die Erstellungszeit mit als Zeit auszeichnen, an der zuletzt upgedated wurde. Wie das funktioniert wird hier beschrieben. Aber ich dachte mir: Das muss auch schöner gehen!

Zuerst muss man herausfinden, an welcher Stelle die Meta-Informationen der Beiträge generiert werden. Im oben verlinkten Artikel ist das in der functions.php der Fall. Beim Theme twentyfourteen ist das aber nicht so. Deshalb hab ich nach einer Zeichenkette gesucht, die ich kannte:

$ cd /pfad/zum/theme/
$ grep -rl "&lt;span class="entry-date"&gt;" *
image.php
inc/template-tags.php
inc/widgets.php

Die Suche ergab 3 Dateien; die erste und die letzte kann man aber ausschließen. Also muss man in der Datei inc/template-tags.php suchen:

&lt;?php

// Set up and print post meta information.
printf( '&lt;span class="entry-date"&gt;
		&lt;a href="%1$s" rel="bookmark"&gt;&lt;time class="entry-date" datetime="%2$s"&gt;%3$s&lt;/time&gt;&lt;/a&gt;
	&lt;/span&gt;
	&lt;span class="byline"&gt;
		&lt;span class="author vcard"&gt;&lt;a class="url fn n" href="%4$s" rel="author"&gt;%5$s&lt;/a&gt;&lt;/span&gt;
	&lt;/span&gt;',
esc_url( get_permalink() ),
esc_attr( get_the_date( 'c' ) ),
esc_html( get_the_date() ),
esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ),
get_the_author()
);

?&gt;

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