Apache ist ein äusserst exponierter Dienst. Grad auf Servern mit vielen Seiten und zahlreichen PHP-Skripten ist das durchaus die grösste Bedrohung für die Serversicherheit. Daher empfiehlt es sich, der Absicherung von Apache besonders viel Aufmerksamkeit zukommen zu lassen. Eine wichtige Methode der Absicherung ist das chroot, in dem der Apache in ein Unterverzeichnis des Systems gesperrt wird. Gelingt ein Angriff auf ein Webskript, so sind für den Angreifer noch immer weitere Hürden in den Weg gelegt, bevor er sich im System einnisten kann.
Relativ einfach lässt sich ein chroot mittels mod_chroot einrichten. Es gibt auch unzählige Howtos im Internet. Aber leider kein einziges brauchbares. Apache ins chroot sperren ist an sich keine Sache. Die nötigen Pakete installieren, dann noch zwei Konfigurationseinträge vornehmen und gut. Gut? Nein! Denn damit geht eigentlich gar nichts mehr, ausser der Auslieferung statischer Webseiten und ein Bisschen Basis-PHP. Email? Tot! ImageMagick? Tot! Das muss nicht sein. Daher mein Howto für Apache mit mod_chroot, mod_php5, suhosin und PHP im safe_mode:
Zuerst müssen die nötigen Pakete installiert werden:
aptitude install apache2 libapache2-mod-chroot libapache2-mod-php5 php5-suhosin php5-imagick imagemagick dash msttcorefonts
Weitere PHP-Module können nach Bedarf installiert werden, wie z.B. php5-gd php5-imap php5-ldap php5-mcrypt php5-mysql. Vorsicht ist bei suhosin geboten, einige grössere PHP-Applikationen bekommen dadurch Probleme. Entsprechende Workarounds müssen dann per individueller Konfiguration eingebaut werden. Die meisten wichtigeren Applikationen haben in ihrer Hilfe oder im Supportbereich entsprechende Informationen.
Ein erster Härtungsschritt ist, dass Apache der Zugang zu einer Shell entzogen wird. Eine Shell ist nicht notwendig und nur ein weiterer potentieller Unsicherheitsfaktor. Also:
usermod -s /bin/false www-data
Nun müssen die Module aktiviert werden:
a2enmod mod_chroot && a2enmod php5
In der Datei /etc/apache2/apache2.conf muss folgende Zeile eingefügt werden:
ChrootDir /var/www
Als nächster Schritt wird das chroot gebaut. Das ist ein sehr langer und aufwändiger Prozess. Denn ins chroot müssen sämtliche ImageMagick-Binaries sowie ein SMTP-Server samt ihrer Abhängigkeiten kopiert werden. Ich hab das chroot wie schon bei Teamspeak mit den Thread Local Storage Bibliotheken gebaut. XEN-User sollten davon Abstand nehmen und die "normalen" Bibliotheken verwenden. Als Mini-Mailserver habe ich mich für esmtp entschieden, wer andere vorlieben hat, darf sich natürlich auch gerne ssmtp anschauen oder versuchen mini_sendmail zum Laufen zu überreden.
Mailer vorbereiten
Leider akzeptiert Debian nur die Installation eines MTA gleichzeitig. Da man als Systemmailer wohl lieber Postfix oder Exim einsetzt, muss hier etwas getrickst werden. Verwendet hier bitte für den Download der Pakete (auch wenn sie recht klein sind) den Debian Mirror EURER Wahl, damit sich die Last entsprechend verteilt. Ausserdem muss auf die Versionsnummer acht gegeben werden, die kann sich natürlich mit der Zeit ändern. .deb-Pakete sind mit dem Packer ar gepackt, dieser sollte standardmässig auf jedem Debian-System installiert sein.
mkdir ~/esmtp
cd ~/esmtp
wget http://mirror.switch.ch/ftp/mirror/debian/pool/main/e/esmtp/esmtp_0.5.1-4.1_i386.deb
wget http://mirror.switch.ch/ftp/mirror/debian/pool/main/libe/libesmtp/libesmtp5_1.0.4-2_i386.deb
ar xv esmtp_0.5.1-4.1_i386.deb
tar -zxf data.tar.gz
ar xv libesmtp5_1.0.4-2_i386.deb
tar -zxf data.tar.gz
Basis-Chroot bauen
Bei sämtlichen Befehlen, die nun folgen, wird davon ausgegangen, dass man sich im Verzeichnis /var/www befindet. Ist dem nicht so, so stimmen natürlich die relativen Pfade nicht mehr und das Howto schlägt fehl. Wie schon eingangs erwähnt, sollten XEN-User aus Performancegründen nicht die TLS-Bibliotheken verwenden.
cd /var/www
mkdir bin etc lib tmp usr
mkdir -p lib/tls/i686/cmov usr/lib/i686/cmov var/lib/php5 var/log/apache2 var/run
chown www-data:www-data tmp
chown www-data:www-data var/lib/php5
chown www-data:www-data var/log/apache2
chown www-data:www-data var/run
touch var/run/apache2.pid
ln -sf var/run/apache2.pid /var/run/apache2.pid
cp /bin/dash bin
cd bin
ln -sf dash sh
cd ..
cp /etc/mime.types etc
grep www-data /etc/passwd > etc/passwd
cp /lib/ld-linux.so.2 lib
cp /lib/libgcc_s.so.1 lib
cp /lib/libnss_dns.so.2 lib
cp /lib/tls/i686/cmov/libc.so.6 lib/tls/i686/cmov
cp /lib/tls/i686/cmov/libdl.so.2 lib/tls/i686/cmov
cp /lib/tls/i686/cmov/libpthread.so.0 lib/tls/i686/cmov
cp /lib/tls/i686/cmov/libresolv.so.2 lib/tls/i686/cmov
cp /usr/lib/libz.so.1 usr/lib
cp /usr/lib/i686/cmov/libcrypto.so.0.9.8 usr/lib/i686/cmov
cp /usr/lib/i686/cmov/libssl.so.0.9.8 usr/lib/i686/cmov
Dash wird als Shell mit minimalem Speicherbedarf installiert. Leider benötigt esmtp zwingend eine Shell, ansonsten verweigert er den Dienst. Dies ist natürlich ein klarer Sicherheitsmangel, der durch Workarounds wie safe_mode behoben werden muss.
Nun wird der Mailer ins chroot kopiert:
cp ~/esmtp/usr/bin/esmtp bin
cp -r ~/esmtp/usr/lib usr/lib
Und als nächstes wird der Mailer konfiguriert. Unter Annahme, dass auf dem Server z.B. ein Postfix oder Exim als Mailserver läuft, muss dazu die Datei /var/www/etc/esmtprc mit folgendem Inhalt erstellt werden:
hostname = 127.0.0.1:25
starttls = disabled
Ausserdem ist jetzt der Zeitpunkt gekommen, um PHP mitzuteilen, wie es mailen soll. Ausserdem kann man bei der Gelegenheit auch weitere Absicherungen vornehmen und z.B. den safe_mode einschalten. Dazu müssen ein paar Direktiven in der Datei /etc/php5/apache2/php.ini angepasst oder eingefügt werden. Beachte, dass die Shell in /bin liegt, während als safe_mode_exec_dir /usr/bin konfiguriert wird. PHP-Skripte können also nicht auf die Shell zugreifen.
safe_mode = On
safe_mode_exec_dir = /usr/bin
expose_php = Off
display_errors = Off
log_errors = On
sendmail_path = /bin/esmtp -t
ImageMagick und Schriften
Es müssen ein paar weitere Bibliotheken sowie die benötigten ImageMagick-Binaries ins chroot kopiert werden:
mkdir -p usr/lib/mime/packages/
mkdir usr/bin
cp /lib/tls/i686/cmov/libm.so.6 lib/tls/i686/cmov/
cp /usr/lib/libMagick.so.9 usr/lib/
cp /usr/lib/liblcms.so.1 usr/lib/
cp /usr/lib/libtiff.so.4 usr/lib/
cp /usr/lib/libjasper-1.701.so.1 usr/lib/
cp /usr/lib/libjpeg.so.62 usr/lib/
cp /usr/lib/libpng12.so.0 usr/lib/
cp /usr/lib/libXext.so.6 usr/lib/
cp /usr/lib/libXt.so.6 usr/lib/
cp /usr/lib/libSM.so.6 usr/lib/
cp /usr/lib/libICE.so.6 usr/lib/
cp /usr/lib/libX11.so.6 usr/lib/
cp /lib/libbz2.so.1.0 usr/lib/
cp /usr/lib/libxml2.so.2 usr/lib/
cp /usr/lib/libfreetype.so.6 usr/lib/
cp /lib/tls/i686/cmov/libdl.so.2 usr/lib/
cp /usr/lib/libXau.so.6 usr/lib/
cp /usr/lib/libXdmcp.so.6 usr/lib/
cp /usr/lib/mime/packages/imagemagick usr/lib/mime/packages
cp /usr/bin/animate usr/bin
cp /usr/bin/compare usr/bin
cp /usr/bin/composite usr/bin
cp /usr/bin/conjure usr/bin
cp /usr/bin/convert usr/bin
cp /usr/bin/display usr/bin
cp /usr/bin/identify usr/bin
cp /usr/bin/import usr/bin
cp /usr/bin/mogrify usr/bin
cp /usr/bin/montage usr/bin
Wer noch Schriften braucht, kann diese nach Bedarf installieren. Die Dateinamen der Schriftdateien müssen komplett in Kleinbuchstaben gehalten sein.
mkdir -p usr/share/fonts/truetype/msttcorefonts/
cp /usr/share/fonts/truetype/msttcorefonts/verdana.ttf usr/share/fonts/truetype/msttcorefonts/
DocumentRoot
Der Startvorgang des Apache verläuft in etwa folgendermassen:
- Apache startet ausserhalb der chroot-Umgebung und wertet die Konfiguration in /etc/apache2 aus.
- Apache schreibt sein PID in die vorgegebene pid-Datei
- Apache prüft die Existenz der DocumentRoot-Verzeichnisse gemäss Konfiguration in den vhosts.
- Apache öffnet die Logfiles gemäss Konfiguration in den vhosts.
- Apache wechselt ins chroot.
- Apache öffnet die Sockets.
- Apache wechselt zu einem unpriviliegierten User.
- Apache ist bereit. Sämtliche Anfragen werden nun im chroot bearbeitet. Die Ausführung von PHP-Skripten findet nun im chroot statt.
Folglich muss von den DocumentRoot-Verzeichnissen eine Schatteninstallation und eine Life-Installation vorgenommen werden. Wird in der Apache-Konfiguration z.B. die Direktive
DocumentRoot /var/www/htdocs/myhost
eingetragen, müssen folgende Verzeichnisse erstellt werden:
mkdir -p /var/www/htdocs/myhost
mkdir -p /var/www/var/www/htdocs/myhost
Effektiv arbeiten wird Apache dann mit dem Verzeichnis /var/www/var/www/htdocs/myhost, dorthin gehören folglich alle HTML-Dateien.
Apache starten, stoppen, neu laden
Jetzt kann man mal die ganze Sache testen und Apache starten. Ich habe festgestellt, dass mod_chroot leider die reload- und restart-Befehle zerschiesst. Folglich bleiben nur noch start und stop übrig. Um eine geänderte Konfiguration einzulesen, bleibt folglich leider keine andere Möglichkeit, als Apache erst zu stoppen und dann wieder zu starten. Bei stärker frequentierten Seiten freuen sich da vermutlich nicht alle User darüber. Sorry, aber dafür gibt's wohl keine Lösung.
/etc/init.d/apache2 start
/etc/init.d/apache2 stop