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

mutt: gesamte Email in Datei speichern

Will man bestimmte Teile einer Mail in eine Datei speichern, kann man mittels v alle Parts anzeigen lassen und dann mit speichern. Dabei werden aber keine Header gespeichert.

Will man die komplette Mail inklusive Header und Anhängen als Datei speichern kann man nutzen (Pipe bzw. senkrechter Strich). Dieser bewirkt, dass die Mail über STDIN an einen Befehl geschickt wird – daher öffnet sich eine Kommandozeile. Dort gibt man dann einfach folgendes ein: 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

getssl: Let’s Encrypt ohne Python-Client

Vorwort

Nachdem Mozilla starke Kritik an Wosign und Startcom geübt hat, entfernte nun Apple als erstes die Zertifizierungsstelle aus seinen Trust-Stores. Für den Otto-Normal-Verbraucher heißt das nun, dass die Zertifikate von StartCom und Wosign faktisch wertlos sind; es ist ungewiss, ob sich die CA davon wieder erholt, auch wenn die Maßnahme vorerst auf ein Jahr begrenzt ist, und sich WoSign dann erneut einer unabhängigen Überprüfung unterziehen lassen kann.

Damit bleibt Let’s Encrypt die letzte mir bekannte Möglichkeit, kostenlos SSL-Zertifikate zu nutzen. Und bei aller berechtigten Kritik an dem Vorgehen, Zertifikte nur für 90 Tage auszustellen und diese mit einem Client automatisiert erneuern zu lassen, ist das Verfahren zumindest transparent und quelloffen.

Wem der native Python-Client nicht zusagt, der kann aus einer Vielfalt von alternativen Clients wählen. Ich habe mich für getssl entschieden, und möchte hier kurz eine Einführung geben.

Installation

Getssl ist ein simples Bash-Skript – daher kann auch ein unerfahrener Entwickler in den Code schauen und nachvollziehen, was dort eigentlich passiert. Installiert wird das Skript folgendermaßen:

curl --silent https://raw.githubusercontent.com/srvrco/getssl/master/getssl &gt; /usr/local/sbin/getssl
chmod 700 /usr/local/sbin/getssl

Anschließend kann man das Skript mit -h aufrufen, um sich verfügbare Parameter ausgeben zu lassen:

$ getssl -h getssl ver. 1.61 Obtain SSL certificates from the letsencrypt.org ACME server Usage: getssl [-h|--help] [-d|--debug] [-c|--create] [-f|--force] [-a|--all] [-q|--quiet] [-Q|--mute] [-u|--upgrade] [-U|--nocheck] [-w working_dir] domain Options: -h, --help Display this help message and exit -d, --debug Outputs debug information -c, --create Create default config files -f, --force Force renewal of cert (overrides expiry checks) -a, --all Check all certificates -q, --quiet Quiet mode (only outputs on error, success of new cert, or getssl was upgraded) -Q, --mute Like -q, but mutes notification about successful upgrade -u, --upgrade Upgrade getssl if a more recent version is available -U, --nocheck Do not check if a more recent version is available -w working_dir Working directory weiterlesen

Firefox: Alte iLO-Versionen aufrufen

Bei älteren iLO-Versionen kann es vorkommen, dass der Firefox  beim Herstellen der HTTPS-Verbindung den SSL-Fehler SSL_ERROR_BAD_MAC_ALERT bringt. Hintergrund ist, dass TLS-Versionen älter als 1.2 von Firefox blockiert werden.

Das kann man umgehen, indem man die entsprechenden Hosts in die Ausnahmenliste einträgt: 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

Postfix: message_size_limit pro Domain

Postfix bietet per default nur eine globale Einstellung zur Limitierung der Größe von Nachrichten. Manchmal braucht man das aber etwas granularer. Um das zu realisieren kann man „Policy-Delegation“ nutzen, wodurch Postfix Entscheidungen an einen externen Policy-Server weiterreichen kann. Siehe auch.

Um die Anforderung „message_size_limit pro Domain“ umzusetzen braucht es nicht viel – ein paar Zeilen Perl reichen:

#!/usr/bin/env perl # # Ein simpler Policy-Server für Postfix, der message_size_limit pro Domain # implementiert. use strict; # Hier ist die Definition der Domains mit Limit (in Bytes) my %hashConfig = ( "marco-pc-debian.localdomain" => 75, "example.org" => 1024, ); my $action; my %attr = (); while( <STDIN> ) { if( /([^=]+)=(.*)\n/ ) { $attr{$1} = $2; } elsif( $_ eq "\n" ) { $action = "action=OK"; foreach my $domain (keys%hashConfig) { if( $attr{'recipient'} =~ /${domain}$/ ) { if( $attr{'size'} > $hashConfig{$domain} ) { $action = "action=534 message size for this domain is limited to ".$hashConfig{$domain}; } last; } } print $action."\n\n"; exit( 0 ); } } weiterlesen

Click’n’Load mit entfernten JDownloader- oder pyLoad-Instanzen

Wer pyLoad oder JDownloader auf einem Server oder einem entfernten Gerät benutzt, wünscht sich vielleicht die Click’n’Load-Funktion, die das Hinzufügen von Links sehr einfach macht. Um sie nutzen zu können müssen 2 Dinge gemacht werden: weiterlesen

JDownloader headless auf Debian-/Ubuntu-Server installieren (ohne Xvfb oder VNC)

Ich habe mir zu dem Zweck eine VM mit Ubuntu 16.04 installiert, natürlich eine Minimalinstallation. Als erstes sind ein paar Vorbereitungen zu treffen, wie einen dedizierten Nutzer anzulegen:

$ mkdir /opt/jdownloader
$ useradd -M -d /opt/jdownloader -s /bin/bash jdownloader
$ chown -R jdownloader:jdownloader /opt/jdownloader

Jetzt wird Java installiert (Debian-Nutzer können auch die Version 7 installieren, sofern die 8 noch nicht in den Repositories ist):

$ apt-get install openjdk-8-jre-headless

Anschließend brauchen wir den JDownloader. Ladet euch von der Download-Seite die JAR-Datei herunter (Betriebssystemauswahl: Other), und legt es in den Ordner /opt/jdownloader.

Ist das getan, kann der JDownloader das erste Mal gestartet werden. Dabei wird er sich erstmal selbst installieren und nebenbei auf Updates prüfen:

$ su - jdownloader
$ cd /opt/jdownloader
$ java -jar JDownloader.jar

Ist der Lauf durch, sollte sich der Befehl selbst beendet haben – JDownloader läuft jedoch bereits im Hintergrund weiter. Um sicher zu gehen, dass alle Updates korrekt installiert wurden, kann man den letzten Befehl noch einmal ausführen. Anschließend killt man den JDownloader:

$ ps -ef|grep JDownloader jdownlo+ 5417 1 99 13:22 pts/0 00:00:12 /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java -jar JDownloader.jar -afterupdate $ kill 5417 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