Tag: apache

Hinweis zum Apache Performance Tuning

Wenn beim Starten des Apaches eine Meldung kommt wie diese:

WARNING: ThreadsPerChild of 1024 exceeds ThreadLimit value of 64
threads, lowering ThreadsPerChild to 64. To increase, please see the
ThreadLimit directive.

Und man hat trotzdem in der Config einen ausreichend hohen ServerLimit-Wert und man war auch nicht so unvorsichtig es nur mit einem Restart zu versuchen…

… dann kann die Ursache erstaunlicherweise die Reihenfolge der Anweisungen in der Konfiguration sein!
Jedenfalls kam es bei meiner Konfiguration (Apache 2.2, MPM worker und Solaris) zu dem Effekt, daß der Parameter ServerLimit ignoriert wurde, wenn er nicht vor MaxClients angegeben war…

Kommentare deaktiviert : Mehr...

Apache Logs auf zentralen Loghost verwalten

Das Speichern und Verwalten von Webserver-Zugriffslogs ist trivial:  Man nutzt einfach die Directiven CustomLog und Errorlog im Apache und alles ist erledigt. Als ganz schlauer Admin mit SLES11 ruft man vielleicht noch eben ein
zypper -install webalizer
auf und schon hat man auch noch die Webstatistik impetto.

Gut. Das klappt wirklich so. Nämlich dann, wenn man auf einer Linuxkiste arbeitet und man vielleicht ein paar wenige, selbst verwaltete Webauftritte hat, die auch nicht so hohe Zugriffszahlen aufweisen…

Schluss mit dem Kinderkram!

Meine Ausgangslage sieht aber dann doch etwas anderes aus: Ich betreibe auf 5 Webservern über 600 Webauftritte von einigen Hundert verschiedener Kunden. Diese Webauftritte bestreiten das gesamte Spektrum von einfach bis komplex: Es gibt Webauftritte aus einer handvoll statischer Webseiten genauso wie Webauftritte die mit eigenen CMS- und Redaktionssystemen betrieben werden. (Dabei auch Performancefresser wie Typo3 und WordPress). Auch bei den Webauftritte die nicht auf Basis eines CMS oder Redaktionssystems funktionieren, verwendet die überwiegende Mehrzahl interaktive Skripten (PHP, Perl, Pyton, …).
Einige der Webauftritte verursachen mehrere Hundert GigabyteTraffik pro Monat. Bei ein paar dieser Webauftritte sind die Accesslogfiles pro Monat stets größer als 2 GB. Alles zusammen verzeichnet die Statistik etwa 1 Terabyte Traffik und 37 Millionen Zugriffe im Monat. Und ja, das ganze läuft wirklich  auf nur 5 Servern (und zwar keine teuren Spezialserver, sondern inzwischen ältern Sunserver vom Typ SunFire T2000).

Das Ziel

Durch einen Load-Balancer soll ein Webauftritt von einem der 5 Server bedient werden. Dabei ist selbstverständlich vorher nicht klar welcher Webauftritt durch welchen Server behandelt wird. Jeder Server kann den Request annehmen und bearbeiten. Und beim nächsten Aufruf kann es der nächste Server sein.
Vom Filesystem her arbeiten alle auf denselben Bereich. (Wie das Fileystem redundant organisiert wird ist eine andere Geschichte).
Da jeder Webserver die Zugriffe bearbeiten kann, ist eine lokale Speicherung der Zugriffslogs ungeschickt. Sowohl ein Webmaster einer Domain der etwas nachprüfen will, als auch die automatisierte Auswertung mittels eines Statistikproggrammes wie Webalizer verlangen eine Datei, die alle Zugriffe auf den Webauftritte enthalten. Niemand will auf jedem einzelnen Server nachschauen müssen ob und was da etwa noch steht.
(Ganz abgesehen davon, daß meine Kunden gar keine Zugriffsberechtigung auf die Webserver bekommen).
Ziel ist also: Jeder Webauftritt braucht eine eigene Zugriffslog, die alle Zugriffe verzeichnet, egal welcher Webserver konkret den Request bearbeitete.
Und unter Umständen wird nicht nur die Zugriffslog benötigt, sondern auch die Errorlog.

Weitere Anforderungen:

Die Server sollen nicht auf eine technologische Basis beschränkt sein. Neben den jetzigen 5 Sun-Servern sollen auch andere Server mit anderen Betriebssystemen (SLES10, SLES11, Ubuntu, u.a.) zentral verwaltete Logdateien erstellen.
In Hinblick auf Bedenken des Datenschutzes hinsichtlich der Personenbeziehbarkeit von IP-Adressen sollten diese Rechneradressen anonymisiert werden, soweit dies möglich ist.

Umsetzung

Die Umsetzung erfolgt mit Hilfe eines zentralen Loghosts. Dieser nimmt alle Logmeldungen mit syslog-ng entgegen und schreibt sie in die Zieldateien. Die Webserver spielen dabei die Rolle der “Clients”. Diese senden die Nachrichten über syslog oder syslog-ng an den Loghost.
Bevor ich auf die Apache-Konfiguration eingehe, zunächst zur Konfiguration der Syslog-Dämonen.

Die Syslog-Clients: Die Webserver

Je nachdem auf welchem Betriebssystem gearbeitet wird, steht auf unseren Server entweder syslog oder syslog-ng zur Verfügung. Für den Loghost macht es keinen Unterschied, welche Software die Clients nutzen.

Clients mit syslog

Clients mit dem normalen Syslog brauchen folgende Zeilen in der Konfiguration syslog.conf:

   local0.*	@LOGHOST.HOSTNAME
   local1.*	@LOGHOST.HOSTNAME
   local2.*	@LOGHOST.HOSTNAME
   local3.*	@LOGHOST.HOSTNAME

Die Facilities local0, local2 werden verwendet für Errorlogs, während die Facilities local1 und local3 für Access-Logs genutzt werden.
Warum wir jeweils zwei Facilities verwenden erkläre ich weiter unten.

Clients mit syslog-ng

Wir modifizieren die Default syslog.conf um folgende Einträge:

Modifizierter Options-Bereich oben:

#
# Global options.
options {
        long_hostnames(off);
        time_reopen(10);
        time_reap(360);
        log_fifo_size(0);
        sync(0);
        perm(0640);
        stats(3600);
        log_msg_size(32768);
        use_dns(no);
};

Innerhalb der üblichen Filter:


filter f_apache     { facility(local0, local1,local2,local3)
                              and level(info);  };

filter f_local      { facility(local0, local1, local2, local3,
                             local4, local5, local6, local7) and
                             not filter(f_apache);
                         };

Und neu am Ende:

destination webserver { tcp("IP.ADRESSE.LOGHOST"); };
log { source(src); filter(f_apache); destination(webserver); };

Der Loghost

Mit folgender Konfiguration des syslog-ng’s wird dafür gesorgt, dass

  • Access-Logdateien auf taeglicher Basis
  • Errorlog-Dateien auf monatlicher Basis

entstehen. Die Dateien werden dabei in ein Logverzeichnis ( /proj.stand/log/access und /proj.stand/log/errors/ ) geschrieben. Im Falle der Errorlogs in ein Verzeichnis pro Monat im Falle der Accesslogs in ein Verzeichnis $Monat/$Tag.
Ein Aufräumskript sorgt dafuer, dass die Logdateien nach einer gewissen Zeit gelöscht werden.

Server-Konfiguration in /etc/syslog-ng/syslog.conf:

source net {
        tcp(ip("0.0.0.0") port(514));
        udp(ip("0.0.0.0") port(514));

};
 

Hier definieren wir die Quelle: Wir betrachten Syslogmessages die sowohl über UDP als auch über TCP kommen.

template t_accesslog {
        template("$MSGONLY\n"); template_escape(no);
};
template t_errorlog {
        template("$HOST $MSGONLY\n"); template_escape(no);
};
template t_hostactivity {
        template("$STAMP\t$HOST\t$PROGRAM\t$FACILITY\n"); template_escape(no);
};

Diese drei Anweisungen definierten das Format der Messages wie sie gespeichert werden sollen.

destination d_apacheerror {
        file("/proj.stand/logs/errors/$MONTH/$PROGRAM.log" template(t_errorlog));
};
destination d_apacheaccess {
        file("/proj.stand/logs/access/$MONTH/$DAY/$PROGRAM.log" template(t_accesslog));
};
destination d_sn_apacheerror {
        program("/proj.stand/bin/dest-error-filter.pl $MONTH" template(t_errorlog));
};
destination d_sn_apacheaccess {
        program("/proj.stand/bin/dest-access-filter.pl $MONTH $DAY" template(t_accesslog));
};

destination d_hostactivity {
        file("/proj.stand/logs/hostactivity/activity-$YEAR-$MONTH-$DAY.log" template(t_hostactivity));
};
destination netaccess {
        file("/proj.stand/logs/unknown/$FULLHOST.log");
};

Die Destinations definieren wohin wir Zugriffe speichern wollen und welches Format diese dabei haben.
Zu beachten ist auch hier, daß ich im Falle der Error- und der Accesslogs jeweils zwei Varianten betrachte: destination d_apacheaccess vs. destination d_sn_apacheaccess und destination d_apacheerror vs. destination d_sn_apacheerror.
Im ersten Fall speichere ich die Logmessages direkt in eine Datei, in zweiten Fall sende ich die Messages an ein Programm. (Siehe weiter unten).

Die beiden letzten Destinations dienen nur noch zu Kontrollzwecken. Mit der Destination d_hostactivity{}, welche Server konkret Apache-Anfragen senden und also aktiv sind.
Damit kann ich beim Einsatz des Webclusters feststellen, ob einzelne Server überhaupt aktiv sind und wie häufig sie es in Relation zu anderen Servern sind. (Dadurch kann ich wiederrum Rueckschlüsse auf das LoadBalancing fuehren.)
Die Destination netaccess nutz ich dagegen um solche Hosts abzufangen, die Nachrichten an meinen Loghost senden, aber nicht in dem erlaubten Subnetz IP.WEBSERVER.SUBNETZ.0 sind.

Nun, da ich weiss, wohin gespeichert wird, muss ich noch die Filter definieren:

filter f_apacheerror {
        facility(local0) and
        level(info) and
        netmask(IP.WEBSERVER.SUBNETZ.0/24);
};
filter f_apacheaccess {
        facility(local1) and
        level(info) and
        netmask(IP.WEBSERVER.SUBNETZ.0/24);
};
filter f_sn_apacheerror {
        facility(local2) and
        level(info) and
        netmask(IP.WEBSERVER.SUBNETZ.0/24);
};
filter f_sn_apacheaccess {
        facility(local3) and
        level(info) and
        netmask(IP.WEBSERVER.SUBNETZ.0/24);
};

Die Filter definieren Bedingungen die in der folgende Verarbeitung des Syslogstreams zum Zuge kommen.
IP.WEBSERVER.SUBNETZ.0 enthält natürlich die IP-Adresse des Subnetzes in dem die eigenen Server stehen.
Wenn die jeweilige Filterbedingung erfüllt ist, dann wird die Messages an die Destination weitergeleitet:

log {
        source(net);
        filter(f_apacheerror);
        destination(d_apacheerror);
        destination(d_hostactivity);
        flags(final);
};
log {
        source(net);
        filter(f_sn_apacheerror);
        destination(d_sn_apacheerror);
        destination(d_hostactivity);
        flags(final);
};
log {
        source(net);
        filter(f_sn_apacheaccess);
        destination(d_sn_apacheaccess);
        destination(d_hostactivity);
        flags(final);
};
 log {
        source(net);
        filter(f_apacheaccess);
        destination(d_apacheaccess);
        destination(d_hostactivity);
        flags(final);
};
log {
        source(net);
        destination(netaccess);
};

Damit ist die Syslog-Konfiguration für den Loghost vollständig.
(Bitte abernoch weiterlesen – bevor wir den syslog-ng restarten brauchen wir noch 2 Perlskripten. Diese hab ich weiter unten beschrieben).

Zur Erklärung der Facilities: Wie oben bereits geschrieben, werden die Facilities local0, local2 verwendet für Errorlogs, während die Facilities local1 und local3 für Access-Logs genutzt werden.

Warum aber die umständliche Trennung in jeweils zwei Paare mit weiteren Facilities? Normalerweise sollten doch local0 und local1 ausreichen. Denn so schreiben es ja schliesslich auch viele andere Dokumentation im Web zum Thema.
Die Antwort wird ersichtlich, wenn man an das Anfangsszenario denkt und dieses mal in den Apache-Webserver umsetzt. Wenn wir normalerweise für jeden Virtual Host eine eigene Acesslog und eine eigene Errorlog definieren wollen, tun wir dies wie folgt:


...
Errorlog "|/usr/bin/apache-error-logger.pl www.meine-domainname.tld"
TransferLog "|/usr/bin/apache-access-logger.pl www.meine-domainname.tld"
 ...

Was passiert nun, wenn wir dies in einem Apache eintragen, der über 600 Webauftritte verwaltet?
Die Antwort: Beim Start des Apaches werden nun nur für das Logging 1200 Prozesse gestartet, die während der Laufzeit des Apaches mitlaufen!
Damit ist klar, daß man diese Variante für richtiges MassVirtualHosting vergessen kann.
Wir brauchen dort eine bessere, performanceschonendere Lösung.
Wobei wir aber trotzdem diese Variante für “kleine” Server mit nur einem oder wenigen Webauftriotten trotzdem aktiviert lassen wollen.
Die Lösung: Wir definieren die Facilities local0 und local1 dafür auf diese Weise Logfiles zu sichern.
Für Apaches mit vielen Virtual Hosts, die auch alle geloggt werden sollen dagegen, nutzen wir local2 und local3 und machen die Log-Directiven in der Apache-Konfiguration anders.

Die Apache-Konfigurationen

Apache Konfiguration für Webserver mit Logdefinition pro VHOST (wenige VHOSTs)

Die Logs werden in den einzelnen VHOST-Eintraegen definiert.


...
Errorlog "|/usr/bin/apache-error-logger.pl www.meine-domainname.tld"
TransferLog "|/usr/bin/apache-access-logger.pl www.meine-domainname.tld"
 ...

Vorher wird das Logformat wie folgt global festgelegt:

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""

Durch die Einträge werden beim Start des Apache-Servers zwei Prozesse mit den Skripten /usr/bin/apache-access-logger.pl und /usr/bin/apache-error-logger.pl aufgerufen.

Dabei handelt es sich um zwei simple Perlskripten.

apache-access-logger.pl

#!/usr/bin/perl
use Sys::Syslog;
$SERVER_NAME = shift || 'www';
$PRIORITY = 'info';
$FACILITY = 'local1';

openlog($SERVER_NAME, 'ndelay', $FACILITY);
while() {
        chomp;
        if ($_ =~ /^(\d+\.\d+\.\d+\.\d+) /i) {
                $_ =~ s/^(\d+\.\d+\.\d+)\.\d+ /$1.0 /gi;
                # Anonymisieren der IP-Adresse.
                # Nur die letzte Ziffer wird weggemacht
        } else {
                $_ =~ s/^[a-z0-9\-\.]*\.([a-z0-9\-]+)\.([a-z0-9\-]+) /$1.$2 /gi;
                 # Anonymisieren des Hostnamens
                # nur die letzten beiden Bestandteile werden uebernommen
        }

        syslog($PRIORITY,$_);

}
closelog;

Es gibt eine rege Diskussion darüber ob die IP-Adresse, bzw. der Rechnername im Sinne des Datenschutzes erfasst werden darf oder nicht. Diese Diskussion soll jedoch hier nicht weiter ausgefuehrt werden.
Das obige Skript kürzt im Falle einer IP-Adresse diese ab dadurch das die letzte Ziffer auf 0 gesetzt wird. Falls dies weitergehenden Fordungen nicht genüge tut, kann die Regular Expression auch wie folgt geaendert werden:

$_ =~ s/^(\d+\.\d+)\.\d+\.\d+ /$1.0.0 /gi;

(Vgl: auch: ZENDAS: Erstellung anonymisierter Apache Logfiles)
Im Falle dass ein Rechnername angegeben ist, wird diese bis auf die Subdomain gekürzt.

apache-error-logger.pl

#!/usr/bin/perl
use Sys::Syslog;
$SERVER_NAME = shift || 'www';
$PRIORITY = 'info';
$FACILITY = 'local0';

# Sys::Syslog::setlogsock('unix');
openlog($SERVER_NAME, 'ndelay', $FACILITY);
while() {
        chomp;
        syslog($PRIORITY,$_);
}
closelog;

Anmerkung: Im Falle von Fehlern anonymisiere ich die Rechneradressen nicht! Denn Fehler sollten garnicht auftreten. Wenn diese auftreten, ist es notwendig alle Daten der Requests zu haben. Auch die vollständige IP-Adresse.

Apache Konfiguration für Webserver mit globaler Logdefinition (viele VHOSTs)

In dieser Variante enthalten die einzelnen VHOSTs keine eigene Log-Directiven. (Man kann dies aber durchaus trotzdem tun und somit beide Verfahren mischen. Dies macht zum Beispiel dann Sinn, wenn man fuer einzelne VHOSTS eine eigene Errorlog haben moechte).

Der Aufruf im Apache erfolgt über die globale Definition in solcher Form:

ErrorLog "|/usr/bin/apache-vhosterror-logger.pl MEIN_HOSTNAME"
LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
CustomLog "|/usr/bin/apache-vhostaccess-logger.pl MEIN_HOSTNAME" vhost_combined

Auch hier hab ich zwei Perlskripten erstellt. Diese unterschieden sich von den beiden obigen nur dadurch, daß ich hier auf die Anonymisierung verzichte und andere Facilities angebe. (Die Anonymisierung erfolgt auf der Loghost-Seite, damit ich auf der Seite der Webserver etwas Performance spare. Selbst wenn es nur Mikrosekunden sind… ).

apache-vhostaccess-logger.pl

#!/usr/bin/perl
use Sys::Syslog;
$SERVER_NAME = shift || 'www';
$PRIORITY = 'info';
$FACILITY = 'local3';

openlog($SERVER_NAME, 'ndelay', $FACILITY);
while() {
        chomp;
        syslog($PRIORITY,$_);
}
closelog;

apache-vhosterror-logger.pl

#!/usr/bin/perl
use Sys::Syslog;
$SERVER_NAME = shift || 'www';
$PRIORITY = 'info';
$FACILITY = 'local2';

openlog($SERVER_NAME, 'ndelay', $FACILITY);
while() {
        chomp;
        syslog($PRIORITY,$_);
}
closelog;

Filter-Skripte auf Loghost für Apache Mass-VHosting

Auf dem LogHost müssen nun noch die Filterskripte definiert werden, die alle Nachrichten der Webserver erhalten.
Syslog-ng kann leider keine Ergebnisse von RegExps in dessen Filtern als Variable weiterverarbeiten. Deswegen wird dann als “Destination Driver” program() verwendet: “program() Forks and launches the specified program, and sends messages to its standard input.
Diese Nachrichten enthalten im Falle der Accesslogs Dank der LogFormat-Angabe in der ersten Spalte die Angabe des Namen des Webauftritts.
Danach wird gefiltert.

dest-access-filter.pl

#!/usr/bin/perl
use IO::Handle;

$TARGET_DIR = "/proj.stand/logs/access/";
$MONTH = shift;
$DAY = shift;

my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
$mon++;
$MONTH = $mon if (not $MONTH);
$DAY = $mday if (not $DAY);

$SIG{ALRM}      = sub { &doTimeout; };
alarm(60*60);

$daydir =  $TARGET_DIR.$MONTH."/".$DAY;
$monthdir = $TARGET_DIR.$MONTH;
if (not (-d $monthdir)) {
        mkdir($monthdir);
}
if (not (-d $daydir)) {
        mkdir($daydir);
}

while() {
        chomp;
        # Bei Servern auf Basis von SUN wird u.a. durch die MSGId eine Spalte vor den
        # Syslogeinztragen gestellt.
        # Diese kann hier weggefiltert werden:
        $_ =~ s/^\[ID ([^\]]*)\] //gi;

        ($vhost,$userhost,$rest) = split(/\s+/,$_,3);

        if ($userhost =~ /^(\d+\.\d+\.\d+\.\d+)$/i) {
                $userhost =~ s/^(\d+\.\d+\.\d+)\.\d+$/$1.0/gi;
                # Anonymisieren der IP-Adresse.
                # Nur die letzte Ziffer wird weggemacht
        } else {
                $userhost =~ s/^[a-z0-9\-\.]*\.([a-z0-9\-]+)\.([a-z0-9\-]+)$/$1.$2/gi;
                 # Anonymisieren des Hostnamens
                # nur die letzten beiden Bestandteile werden uebernommen
        }
        $vhost = "unknown" if (not $vhost);
        $target = $daydir."/".$vhost.".log";
        open(my ($fh),">>$target");
        $fh->autoflush(1);
        print $fh "$userhost $rest\n";

        $mday = (localtime(time))[3];
        if ($mday != $DAY) {
                exit;
        }
}
exit;

sub doTimeout {
        exit;
}

Zu Erwähnen sind die Timeouts und die Prüfung auf den Tageswechsel. Ebenso wie der Apache startet Syslog den Filterprozess einmal mit den beim Start geltenden Argumenten.
Wenn der Prozess nicht gestoppt wird, läuft dieser Prozess immer weiter. Auch über den Tageswechsel hinaus. Logmeldungen werden dann also ggf. in die falsche Datei gespeichert. Aus diesem Grund, und um zu viele offene Filehandles im Memory zu vermeiden, lass ich das Skript in regelmässigen Abständen und zum Tageswechsel sich selbst beenden. Syslog-NG wird dann den Prozess selbstständig neu starten. Dann aber mit jeweils aktuellen Parametern.

dest-error-filter.pl

#!/usr/bin/perl
use IO::Handle;

$TARGET_DIR = "/proj.stand/logs/errors/";
$MONTH = shift;
my $mon = (localtime(time))[4];
$mon++;
$MONTH = $mon if (not $MONTH);

$SIG{ALRM}      = sub { &doTimeout; };
alarm(60*60);
        # Das Skript soll sich einmal pro Stunde neu starten
$monthdir = $TARGET_DIR.$MONTH;
if (not (-d $monthdir)) {
        mkdir($monthdir);
}

while() {
        chomp;
        $orig = $_;
        if ($_ !~ /^\[/i) {
                # Quellhost ist vor der Zeit angegeben
                # Siehe Einstellung in syslog-ng: template()
                ($quellhost,$rest) = split(/\s+/,$_,2);
        } else {
                $rest = $_;
                $quellhost = "unknown";
        }

        if ($orig =~ /\(server ([a-z0-9\-\.]+):*(\d*)\)/i) {
                $vhost = $1;
        } else {
                $vhost = "";
        }

        if ($vhost) {
                $target = $monthdir."/".$vhost.".log";
        } else {
                $target = $monthdir."/".$quellhost.".log";
        }
        local $fh;
        if (not $tlist->{$target}->{'fh'}) {
                open($fh,">>$target");
                $fh->autoflush(1);
                $tlist->{$target}->{'fh'} = $fh;
        } else {
                $fh = $tlist->{$target}->{'fh'};
        }

        if ($SHOW_SOURCEHOST) {
                print $fh "$orig\n";
        } else {
                print $fh "$rest\n";
        }
        $mday = (localtime(time))[3];
        if ($mday != $DAY) {
                exit;
        }

}
exit;
sub doTimeout {    exit;   }

Wie auch das Skript für die Accesslogs enthält der Filter für die Errorlogs ein Timeout und ein Exit bei dem Tageswechsel.
(Ich verwalte in diesem Skript die Dateihandles etwas anders als bei den Accesslogs, dies tut aber nichts zur Sache und hat als Grund nur das ich an der Stelle später besser diverse Debugausgaben einbauen kann).

Hinweise

Errorlog bei zentralen Logfiles

  • Der Filter für globale Errorslogs filtert den $vhost-Namen optional nicht aus dem Logstream aus, da bei den Einsatz mit Load-Balancern es wichtig sein kann zu wissen, auf welchem Server ein Fehler passierte. Bei Access-Logs dagegen ist dies nicht notwendig.
  • Bei globalen Errorlogs ist die Syntax etwas anders als bei Errorlogs in Virtual Hosts. Eine LogFormat-Directive für Errorlogs gibt es nicht. Aus der Manual:
    It is not possible to customize the error log by adding or removing information. However, error log entries dealing with particular requests have corresponding entries in the access log. For example, the above example entry corresponds to an access log entry with status code 403. Since it is possible to customize the access log, you can obtain more information about error conditions using that log file.
  • Im Falle von Verbindungen die über einen VHOST kommen der SSL verarbeitet, wird die Anfrage jedoch um den Servernamen ergänzt. Diese können wir nutzen, um doch noch wenigstens in diesen Fällen zu filtern.

    Beispiel eines Errorlog-Streams der beim Skript ankommt:

    AA.BB.CC.DD [Tue Dec 15 16:58:16 2009] [info] Client requested a 'session-resume' but we have no such session.
    AA.BB.CC.DD [Tue Dec 15 16:58:16 2009] [info] Initial (No.1) HTTPS request received for child 7 (server www.mein-host.tld:443)
    AA.BB.CC.DD[Tue Dec 15 16:58:16 2009] [info] Subsequent (No.2) HTTPS request received for child 7 (server www.mein-host.tld:443)
    AA.BB.CC.DD [Tue Dec 15 16:58:31 2009] [info] [client AA.BB.CC.FF] (70007)The timeout specified has expired: SSL input filter read failed.
    AA.BB.CC.DD [Tue Dec 15 16:58:31 2009] [info] [client AA.BB.CC.FF] Connection closed to child 7 with standard shutdown (server www.mein-host.tld:443)
    

    Clients auf SLES

    Auf SLES10 erfolgt die Bearbeitung der syslog.conf in der Datei /etc/syslog-ng/syslog.conf.in .
    Die Änderungen werden danach aktiviert durch den Befehl
    SuSEconfig --module syslog-ng

    Auf SLES11 dagegen wird direkt in der /etc/syslog-ng/syslog.conf geändert und der Dämon schlicht über /etc/init.d/syslog restart neu gestartet.

    Clients auf Solaris-Server

    Per Default dendet der Syslog unter Solaris (seit SunOS 5.6 (Solaris 2.5.1) ) nachrichten im Format:

    [ID msgid facility.priority] Nachricht

    Beispiel:

      Jul  9 10:13:06 u5 pseudo: [ID 129642 kern.info] pseudo-device: tod0
      Jul  9 16:14:51 u5 login: [ID 644210 auth.notice] ROOT LOGIN /dev/console
    

    Diese kommen auf dem Loghost dann in der $MSGONLY als solches an. Syslog-NG kann zwar danach filtern mit einer RegExp, jedoch kann syslog-ng den ID-Bestandteil leider nicht selbst entfernen.

    Es gibt zwei Möglichkeiten für SUN-Admins:

    1. Man installiere syslog-ng auf dem Client
    2. Man konfiguriert das Format und hofft, das dieser Folgepatches überlebt ;)

    Ich hab mich für letzteres entschieden. Denn da wir cfengine verwenden um unsere Konfiguration zu verwalten, dürfte damit auch bei wildgewordenen Patches nichts passieren.
    Die Konfigurationsdatei für Nachrichtenformate in syslog unter Solaris ist die Datei
    /kernel/drv/log.conf

    Sie sieht per Default so aus:

    name="log" parent="pseudo" instance="0"
    msgid=1;
    

    Zum Abschalten der MSGId ist der Wert
    msgid=1;
    einfach auf “0″ zu setzen. Damit diese Einstellung aktiv wird, ist ein Reboot notwendig.

Weitere Links und Quellen

1 Kommentar :, , , , , , , , , Mehr...

Die Grenzen des Webservers und darüber hinaus… – Verwaltung von mehr als 256 virtuellen Hosts unter Apache

Einführung

Wer einen Server mit mehr als 200 virtuellen Hosts betreibt wird früher oder später auf unerwartete Probleme treffen. Der Webserver verweigert seinen Dienst, Dateien an denen nichts geändert wurden, können plötzlich nicht mehr gelesen werden und all dies passiert auch noch so, daß man es nicht immer nachstellen kann.

Die Symptome und Hintergründe

Wenn der Webserver beim Aufruf von sonst zugreifbaren Dateien auf einmal nicht mehr lesbar sind und es zu einem Fehler mit einem Code über 400 kommt, kann dies folgende Gründe haben:

  1. Die Datei ist wirklich nicht vorhanden oder nicht lesbar. In der Errorlog finden sich solche Eintraege:
    [Tue Aug 27 10:34:29 2002] [error] [client XXX.XXX.XXX.XXX] File does not exist:
    /irgendwo/irgendwas/5_dokt_on.gif
    [Tue Aug 27 10:34:29 2002] [error] [client XXX.XXX.XXX.XXX] File does not exist:
    /irgendwo/irgendwas/06_sekr_on.gif
    [Tue Aug 27 10:34:29 2002] [error] [client XXX.XXX.XXX.XXX] File does not exist:
    /irgendwo/irgendwas/01_univ_on.gif

    In anderen Worten: Jemand hat einfach eine nicht vorhandene Datei aufgerufen. Entweder ist ein Link falsch, es war ein dummer User, oder aber der Webseitenbastler hat einfach vergessen eine Datei anzulegen oder korrekt zu bennen.
    Als Betreuer der Serversoftware haben wir nichts zu tun. Non est mea culpa.

  2. Es gibt eine .htaccess-Datei, die den Zugriff verhindert. Ist aber eher selten. In der Errorlog sieht dies so aus:
    [Tue Aug 27 10:19:24 2002] [error] [client XXX.XXX.XXX.XXX] client denied by server
    configuration: /EN/index.shtml
    [Tue Aug 27 10:19:29 2002] [error] [client XXX.XXX.XXX.XXX] client denied by server
    configuration: /EN/pic/pfeil3.gif

    Hier kann der Client nicht auf die Dateien zugreifen, weil es aufgrund von Serverinstellungen explizit verboten ist. Entweder gibt es eine Datei .htaccess im Webverzeichnis, der die Zugriffsrechte einschränkt, oder aber in der Konfiguration des Webserver ist eine entsprechende Einstellung. Das obige Beispiel war von einer .htaccess-Datei generiert, wo der Zugriff auf gewisse IP-Adressen beschraenkt war. Folgendes Beispiel zeigt den verbotenen Zugriff auf eine Datei, die bereits aus der httpd.conf verboten wird:

    [Tue Aug 27 10:43:04 2002] [error] [client XXX.XXX.XXX.XXX] client denied by server
    configuration: /proj/webbin/cgi-bin/formmail.pl

    Man sieht in der Log keinen Unterschied zu dem vorherigen Beispiel. Hier jedoch wurde der Zugriff in der httpd.conf durch folgende Einstellung verhindert (die uebrigens bei allen bekannten unsicheren Skripten zu empfehlen ist):

    <Location /cgi-bin/formmail*>
       Deny from all
       ErrorDocument 403 http://www.meine_domain.tld/errorskript.shtml
    </Location>
    <Location /cgi-bin/phf*>
       Deny from all
       ErrorDocument 403 http://www.meine_domain.tld/errorskript.shtml
    </Location>

    Als Webmaster kann man nun zwei Dinge tun: Die Achseln zucken und sich darüber feuen, dass der Zugriffsschutz funktionierte, oder aber diesen anpassen, wenn er zu streng ist.

  3. Alle Filesystem-Handles, die dem Apache zur Verfügung stehen, werden bereits genutzt. In der Errorlog sieht dies bei einem Solaris-System und Apache 1.3.26 wie folgt aus:
    [Tue Aug 27 09:06:57 2002] [error] [client XXX.XXX.XXX.XXX] (2)No such file or
    directory: file permissions deny server access: /irgendwo/irgendwas/infopack.pdf
    [Tue Aug 27 09:07:13 2002] [error] [client XXX.XXX.XXX.XXX] (2)No such file or
    directory: file permissions deny server access: /irgendwo/irgendwas/index_e.html

    Diese Meldungen treten dabei recht gehäuft auf… Ausserdem stellen wir bei der Ansicht der Dateien und Verzeichnisse fest: Alles ist lesbar, ggf. sogar für alle User auf dem Filesystem. Es gibt eigentlich keinen Grund, warum die Datei nicht lesbar sein sollte.

    Wenn sowas passiert haben wir möglicherweise Problem: Wir erreichen die Grenzen unseres Systems. Und wir sind da nicht die ersten. In der Bug-Datenbank von Apache finden sich bereits Hinweise und Fragen hierzu. Beispiele:

    Die dort vorgeschlagenen Lösungen dort sind jedoch nicht gerade prickelnd.

Die Grenzen des Systems

Das Problem tritt laut Apache.org (FAQ) je nach OS ab 128 bis 250 virtuellen Hosts auf, welche eigene Logdateien haben. Vergleiche:

Je nach OS ist die maximale Anzahl der virtuellen Hosts, die eigene Logdateien benutzen, ebenfalls begrenzt durch die Anzahl der verfuegbaren File-Descriptoren. Der Apache kann nicht mehr als X Files gleichzeitig geöffnet haben. Diese Anzahl haengt ab vom OS und den zur Verfügung stehenden Ressourcen, die den Webserver zugewiesen werden:

Anzahl der offenen Dateien <= Soft Limit <= Hard Limit <= Kernel Limit

Schaut man sich diese bei unterschiedlichen OS an, kommt man zu folgenden Zahlen für die maximal möglichen Filehandles, die offen sein koennen:

BSDI: 240
FreeBSD: 240
Linux: 256
Solaris: 240
AIX bis 3.2: 128
ab 4.1.5: 2000

Lösungen

Natuerlich kann man der Lösung folgen, dass man keine eigenen Logdateien mehr für die virtuellen Hosts zulaesst. Stattdessen läßt man alles in der Standardlog-Datei speichern. Diesen Tipp kann man dann auch bei der Apache-FAQ nachlesen. Schliesslich fallen damit gleich eine grosse Anzahl von Filehandles die nur für die Verwaltung der Logfiles benutzt werden, weg. Jedoch ist dieser Tipp nicht unbedingt immer gut:

Wer bereits über etwa 240 virtuelle Hosts auf den Webserver betreibt, hat in der Regel auch entsprechend viele Zugriffszahlen, worunter auch ein erkleklicher Anteil an fehlerhaften Anfragen und Brute-Force-Attacken auf CGI- und PHP-Skripten zu finden sind. Wird jeder Zugriff auf alle Hosts in einer einzigen Logdatei gespeichert, kann diese sehr schnell sehr gross werden. Wenn die Datei grösser wird, als wie das OS es verkraften kann (bei alten UNIX- und Linuxversionen und bei normalen Windowsversionen liegt die Grenze bei 2 GB), dann kann es zu einem Crash des Webservers kommen. Wenn man diese Moeglichkeit also nutzt, muss man also unbedingt darauf achten, dass man die “zentrale Logdatei” wieder aufsplittet, die Logs also nicht in eine normale Datei geschrieben werden, sondern in ein Skript, das den <STDIN> verteilt.

Apache bietet seit der Version 1.3 hierzu ein eigenes Shell-Skript an, welches in Apache-Sourceverzeichnis src/support/split-logfile zu finden ist. Damit dieses funktioniert, muss man in der httpd.conf die Einstellung für das Logfile-Format so aendern, dass der Hostname am Anfang steht.

Beispielsweise das Common Log Format:

LogFormat	"%v %h %l %u %t \"%r\" %>s %b"

und damit dann den Aufruf von split-logfile über TransferLog:

TransferLog "| /pfad/zu/split-logfile.pl"

Damit es jedoch nicht zu Nebeneffekten kommt, duerfen bei diesen Fall in den virtuellen Hosts keine eigenen TransferLog’s mehr angegeben sein, da dann die Summe der Filediscriptoren doch wieder über die kritische Grenze steigt.

Diese Lösung ist ansonsten relativ praktikabel. Sie ist jedoch nur das Verschieben des Menetekels auf spaetere Zeiten und auf einen anderen Bereich. Zudem gelten auch für diesen Prozess Filesystem-Beschraenkungen, die zur Folge haben, dass nicht alle Logdateien vollstaendig geschrieben werden.

Das Skript split-logile ist ein Perlskript, bei welchem die Summe der Filehandle abhaengig ist von den Kernel-Parametern im OS. Mit Hilfe des Shellkommandos ‘limit’ (bzw. ‘limits’ oder ‘ulimit’) kann man sich die Zahl der Gesamt zur Verfuegung stehenden Filediscriptoren anzeigen lassen. Beispiel unter Solaris:

xwolf@eisbaer: 16:28 [~] > limit
cputime         unlimited
filesize        unlimited
datasize        2097148 kbytes
stacksize       8192 kbytes
coredumpsize    0 kbytes
vmemoryuse      unlimited
descriptors     1024
xwolf@eisbaer: 16:28 [~] >

Reicht auch diese Gesamtzahl nicht aus, kann man versuchen, diese Zahl durch Neucompilierung des Kernels zu aendern. Empfehlen wuerde ich dies jedoch nicht. Grund: Ein Rechner, der als Webserver im netz erreichbar ist, ist dauernden Angriffen ausgesetzt. Dies erzwingt quasi, dass man bei erscheinen von Patches für das OS diese schnell einbindet – am Besten noch über Autopatch-Mechanismen. Viele dieser Mechanismen gehen jedoch von Standardkonfigurationen des Kernels aus. Hat man einen modifizierten Kernel, kann es unter Umstaenden notwendig sein, von Hand nachzuarbeiten. Und wann wollen Sie in Urlaub gehen? Können Sie sicher sein, daß auch alle ihre Kollegen wissen, was zu tun ist, wenn nach dem Einspielen eines Patches auf einmal ein paar Hundert Domains nicht mehr zugreifbar sind?

Eine weitere Lösungsmöglichkeit liegt darin, zwei oder mehr Apache-Webserver auf einer Hardware zu verwenden. In diesem Fall laege die Grenze der offenen Dateien im OS. Der gravierende Nachteil an dieser Methode liegt jedoch darin, dass nur eine Apache-Instanz auf den Port 80, welcher der Standardport für Web ist, lauschen darf. Alle virtuellen Hosts, die von anderen Apache-Instanzen verwaltet werden wuerden, muessten jeweils auf einen anderen Port liegen.

Meiner Meinung nach besteht die sinnvollste Lösung in einer Hardware-Erweiterung, d.h. dem Aufbau eines Webserver-Parks. In anderen Worten: Jede Server enthaelt eine einzige Apache-Installation mit jeweils maximal 220 – 240 virtuellen Hosts. Hinzu kommt ein Server für die Fallbacksicherung und ein Server als Proxy. Ein weiterer Server sollte für Datenbanken zur Verfuegung stehen.

Beispielsweise würde die Architektur bei 600 virtuellen Hosts wie folgt aussehen:

Der Fallback-Server erhält Zugriff auf alle Webbereiche und kann die Konfigurationsdateien aller Webserver lesen. Eine Überwachung sollte dafür sorgen, daß der Fallback ggf. automatisch die Funktionen eines der Hauptwebserver ersetzt.
Damit der Fallback-Server auf alle Webbereiche und die lokalen Konfigurationen zugreifen kann, muss ein Konzept vorhanden sein, wie die Verzeichnisse und Dateien angeordnet sind.

So sollten auf allen Webservern die Webdateien und Verzeichnisse beispielsweise unter dem Ordner

/proj.stand/websource

abgelegt werden. für einen virtuellen Host www.blafasel.de auf dem Server 1 beispielsweise:

/proj.stand/websource/server1/www.blafasel.de

Dieser Bereich wird auf alle angeschlossenen Server gemountet wie

/proj/websource/server1/www.blafasel.de

Dies hat auch Sicherheitstechnische Vorteile: Kunden kann der Filesystem-Zugang zu den eigentlichen Webservern verschlossen bleiben. Man erlaubt nur das Einloggen auf einen speziell dafür vorgesehenen Server. Die Webserver kann man somit dicht machen, d.h. alle unnötigen Dienste abschalten. Ein weiterer Vorteil liegt auch darin, dass eine optionale globale Suchmaschine leichten Zugriff auf alle Dateien über das Filesysten erhalten koennte.

Im DNS wird ein gesonderte Konfiguration verwendet, damit der Fallbackserver schnell und sogar automatisch anspringen kann: Alle Domainnamen sind CNAME-Records (auch Aliase genannt), die auf einen Server-Namen weisen. Dieser Server-Name ist nun mit der IP des Rechners verbunden.

Beispiel:

;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$ORIGIN         meine_webserver.tld
;   Definition des Servers 1
www1             IN      A       IP.ADR.ESS.E1
www2             IN      A       IP.ADR.ESS.E2

$ORIGIN         domainname1.tld
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
localhost       IN      A       127.0.0.1
www             IN      CNAME   www1.meine_webserver.tld.
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$ORIGIN         domainname2.tld
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
localhost       IN      A       127.0.0.1
www             IN      CNAME   www1.meine_webserver.tld.
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
$ORIGIN         domainname3.tld
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
localhost       IN      A       127.0.0.1
www             IN      CNAME   www2.meine_webserver.tld.
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

(Die Variable $ORIGIN im obigen Beispiel ist eine Abkürzung für einen SOA-Eintrag, in welchem die Nameserver, Version, Refreshrate und andere Daten angegeben sind.)

Die Domains www.domainname1.tld und www.domainname2.tld sind nach dieser Anordnung dem Server 1 zugeordnet und www.domainname3.tld dem Server 2. Wenn nun der Server 1 ausfallen wuerde, muss allein in der Zeile

www2             IN      A       IP.ADR.ESS.E2

die IP-Adresse geaendert werden auf die Adresse des Fallbackservers. In den Eintraegen der eigentlichen Webdomains braucht man nichts aendern.

Entsprechend wie mit den Webdateien wird auch mit den Logdateien und den Serverkonfigurationen und der Serversoftware verfahren. Auf den Bereichen Serversoftware, OS und optionaler Module für die Webserver (wie FastCGI, PHP, SSL usw.) sind alle Server, zzgl. dem Fallback-Server gleichwerige Kopien.

Ein Problem, dass sich hier auftut (was aber auch schon vorher vorhanden war): Zugriffsrechte der User auf dem Filesystem. Hier muss dafür Sorge getragen werden, dass die jeweiligen Webverzeichnisse nur von den Usern selbst und dem Webserver gelesen werden koennen. Leider reicht es nicht aus, mit SUXEC zu arbeiten, da der Webserver dieses nur auf Skripten, nicht jedoch auf Verzeichnisse anwendet und PHP-Skripten überhaupt nicht durch SUEXEC erfasst werden. Lösungen sind hierfür unter Unix/Linux das Setzen von ACLs und das Nutzen von NIS-Maps. Doch dies jetzt zu beschreiben würde den Umfang dieses Artikels sprengen.

Von der Hardware her muessen Proxy und Datenbankserver hoch zuverlässig sein. Alle Webserver muessen sehr sicher gegen Hackerattacken sein. Ich empfehle hier Rechner von Sun mit Solaris, wobei Proxy und Datenbankserver speziell zugeschnitten sein sollten auf die dort laufenden Anwendungen (z.B. ist beim Proxy sehr viel RAM notwendig). Diese Server sollten Rechner der höheren Leistungsklasse (Enterprise, SunBlade1000, Suncat,..) sein. Die Webserver und der Fallbackserver sollten die gleiche Hardware aufweisen. Als Hardware reichen Server der mittleren Leistungsklasse (Enterprise, Sunblade100) mit viel RAM und jeweils mindestens 50 GB Festplattenplatz.

Kommentare deaktiviert :, , Mehr...

Security auf Webservern

Das Betreiben eines Webservers ist heutzutage ziemlich einfach. Jedes Netzwerkfaehige Betriebssystem bietet ein oderer mehrere Produkte, mit denen man mit mehr oder weinger grossem Aufwand seinen eigenen Server betreiben kann. Wenn ich mich zurueckerinnere wie umstaenlich die Einrichtung eines Webservers frueher war – einige erinnern sich vielleicht noch an den ‘httpd’ vom CERN, fuer den es dann irgendwann mal ziemlich viele Patches gab die dann unter einem Hut zusammengefasst wurden und zum “Apache” (kommt von “a patch”) wurden…).

Theoretisch ist das Einrichten eines eigenen Webservers heutzutage wirklich kein Problem mehr. Sowohl die freien Produkte (Apache, Internet Information Server (IIS) von Microsoft) als auch kommerzielle Produkte (etwa dem Netscape Webserver oder andere) sind relativ einfach zu konfigurieren. In der Regel kann man bereits bei der Installation des Betriebssystems einen Webserver mitinstallieren: Windows NT Server installiert den IIS, alle Linux Distributionen sowie alle BSD Derivate installieren einen Apache und auch andere Unixes – etwa Solaris – installieren einen Webserver (entweder eigene oder Apache wie mittlerweile bei Solaris 8 der Fall ist). Fuer eine Intranetloesung reicht das vollkommen und man braucht sich – eine Firewall oder Nichterreichbarkeit von Aussen mal vorausgesetzt – keine weiteren Gedanken mehr machen.
Man darf aber eines nicht vergessen: ein Webserver ist ein Programm, welches DATEN zur verfuegen stellt, welche nach Aussen hin sichtbar sind. Der kleinste Fehler in der Konfiguration genuegt, um ungewollt die Personalakten von Mitarbeitern, Passworten (hoffentlich zumindest verschluesselt) oder andere sensitive Daten fuer jedermann zugaenglich zu machen. Man erinnere sich an verschiedene Faelle im Netz, wo Kundendaten (Teilweise sogar Bankinformationen) zugaenglich waren.
Was ich damit sagen will ist einfach: auch wenn die INSTALLATION einfach ist – die KONFIGURATION muss dafuer umso sorgfaeltiger gemacht werden. Aber die Sicherheit beginnt bereits eine Stufe tiefer – eigentlich sogar zwei Stufen tiefer: einmal beim Betriebssystem selbst und einmal bei der Serversoftware. Wenn das Betriebssystem auf dem der Webserver laufen soll unsicher ist, macht eine noch so gute Konfiguration des Webservers keinen Sinn. Es nuetzt nicht, wenn ich in meinem Haus vergitterte Fenster anbringe und eine Alarmanlage installiere wenn die Tueren keine Schloesser haben oder es soundsoviele Nach- schluessel gibt. Als naechstes muss natuerlich die Serversoftware sicher und stabil sein. Ich erinnere an Microsoft und den IIS Server. Mircosoft selbst hatte es versaeumt, einen Patch fuer den IIS zu installieren und wurde genau ueber dieses Sicherheitsloch das nicht gestopft wurde angegriffen. Die Wahl der Serversoftware sollte – ganz nebenbei bemerkt – nicht unbedingt nach dem Kriterium “sowieso dabei” oder “bequem zu installieren und warten” getroeffen werden sondern AUSSCHLIESSLICH unter dem Aspekt “wie sicher” oder “wie schnell sind Patches da falls doch mal was sein soll”. So hat man im IIS von Microsoft zwar in den letzten beiden Monaten erstaunlich viele Sicherheits- loecher gefunden, die jedoch in relativ kurzer Zeit von Microsoft gestopft wurden. Allerdings mit dem Haken, dass man staendig dahinter sein muss und die Updates auch einspielen muss.

Doch zurueck zum Betriebssystem. Auch das sicherste Betriebssystem nuetzt mir wenig, wenn ich andere Dienste auf dem Server laufen habe, die potentielle Angriffpunkte darstellen koennen (oder tun). Wenn ich also einen FTP Zugang zum Server anbiete ueber den bestimmte Leute ueber ihren Account Daten uploaden koennen (welche vielleicht sogar noch Zugriff auf die Konfiguration vom System oder Webserver haben) ist das vergebliche Liebesmueh’. Wie viele vielleicht wissen, uebertraget FTP (telnet uebrigens auch) alle Daten (auch das PassWORT) im KLARTEXT. Das heisst, ich braeuchte mir nur einen Rechner zu suchen, der irgendwo “zwischen” dem Server und dem Client liegt und die Verbindungen abzuhoeren (technisch absolut das leichteste). Frueher oder spaeter wird jemand das Passwort tippen und ich habe Zugang.
Aehnliches gilt uebrigens fuer POP3 – das am weitesten genutzet Protokoll zum Abholen von Mails von Mailservern. Auch POP3 sendet das eigene Passwort im Klartext ueber das Netz. Abhilfe koennte hier eine gepatchte Version (uebrigens von mir so praktiziert) von einem POP Server schaffen, welcher eine andere Passwortdatenbank verwendet als die Logindaten. Alles was dann noch passieren kann (sofern Benutzer nicht fuer POP und login dasselbe Passwort verwenden) ist, dass jemand die Mails lesen kann.
Immerhin.

Es gibt aber durchaus Dienste, die per se nicht angreifbar sind sondern einfach nur Sicherheitsloecher haben. Lange Zeit (das ist allerdings nun schon sehr lange her) war ‘sendmail’ so ein Kanditat mit vielen Bugs und Sicherheits- loechern ueber die Fremde ins System einbrechen konnten. Nun, um kurz zusammenzufassen: auf einem Webserver (eigentlich: auf jeden Server der einen Dienst im Web anbietet) sollten moeglichst wenig verschiedene Dienste laufen. Einmal um moeglichst wenig Angriffspunkte zu bieten und zum anderen um den Ueberblick leichter behalten zu koennen (3 Serverdienste sind leichter zu warten als 17). Ausserdem sollten moeglichst wenig (wenn ueber- haupt) Benutzer direkten Zugang zum System haben. Und wenn dann nur ueber sichere Verbinungen (etwa durch das verwenden von ssh).

Auch bei der Konfiguration eines Servers kann man viel falsch machen. Da der Apache derzeit der am weitesten verbreitete Webserver ist, moechte ich hauptsaechlich auf den eingehen. Mal ein ganz simples Beispiel: nehmen wir mal an, es gibt Benutzer auf dem System und diese haben im Homeverzeichnis ihr ~/public_html. Niemand kann ihnen verbieten, folgenden Befehl auszufuehren:

              'ln -s / ~/public_html/root'

Diejenigen die sich mit Unix auskennen werden sicher gleich gemerkt haben, was hier passiert. Fuer die anderen: der Befehl ‘ln’ legt sogenannte Symlinks an. Das heisst, eine Datei oder ein Verzeichnis kann ueber einen anderen Namen (der auch ganz woanders liegen kann) zugegriffen werden. In diesem Speziellen Fall wuerde das heissen, dass man – wenn man in das Verzwichnis ‘~/public_html/root’ wechselt in Wirklichkeit im “root” Verzeichnis (der Basis der Baumstruktur unter Unix, also ‘/’) rauskommt. Das heisst nun weiter, das JEDES Verzeichnis (welches Leserechte fuer alle – und das sind in der Regel die meisten) und JEDE Datei (ebenfalls Leserechte fuer alle) eingesehen werden kann. Und zwar von aussen – man brauchts nur zu probieren:

              'http://url.des.servers/~longariva/root'

Erstaunt? Nun, eigentlich sollte jeder daran gedacht haben. Und wenn ich ganz ehrlich bin – auch wenn das jetzt vielleicht boese klingen mag – jemand der das Ganze NICHT durchschaut hat sollte auf keinen Fall einen Server im Netz warten. Es gibt noch eine ganze Reihe anderer Moeglichkeiten wie man ungewollt einen Server unsicher machen kann auf die ich hier nicht weiter eingehen moechte. Grundsaetzlich moechte ich aber als Regel postulieren:

KEIN SERVERDIENST sollte von jemandem gewartet werden, der keine oder wenig Ahnung vom darunterliegenden System hat!

“Ich habe schonmal damit gearbeitet” ist ZUWENIG! Zum Glueck kann der Apache Symlinks verbieten – auch wenn das u.U. an anderer Setelle Probleme machen kann. Aber das ist wieder ein anderes Thema.

Auch nicht in erster Linie von der Serverkonfiguration abhaengig sind die Probleme, die durch (falsche) Verwendung von Skripten, die auf dem Server laufen (CGI, PHP, ASP usw.). Laesst man solche Skripten uneingeschraenkt zu, kann ein Benutzer – absichtlich oder ohne zu wollen – auch sehr viel anrichten. Man darf nicht vergessen: solche Programm laufen AUF dem Server und koennen – je nach Konfiguration – uneingeschraenkt auf Daten, Verzeichnisse usw. zugreifen.
Ich moechte anhand von CGI ein Beispiel anbringen. CGIs koennen beliebige Programme sein – meistens sind es Perl Skripten. Aber auch C Programme, Shell Skripten, ja sogar Visual Basic (etwa auf einem Windows System) koennen fuer CGI verwendet werden. Verwenden wir fuer mein Beispiel ein shell Skript wie folgt:

       #!/bin/sh
       /bin/cat /etc/passwd

ganz kurz – aber mit grosser Wirkung. Legen wir das Skript in das Verzeichnis in dem CGIs liegen und machen es ausfuehrbar (chmod a+x ). Nun fuehren wir es aus. Was passiert? Schockiert? Hoffentlich nicht, denn wenn ja ist der Job als Webadmin wohl doch nicht ganz das richtige… Nun, im Apache kann man einschraenken WO ausfuehrbare Programme liegen duerfen und eigentlich sollten NUR erfahrene Web/CGI Programmierer Skripten fuer das Internet erstellen. Aber manche Kunden moechten ihre eigenen (oder eingekauften) Skripten auf “ihrer Homepage” (dem Server den Sie lieber Leser administrieren) laufen lassen. Sie koennen sicher Mechanismen erfinden um zu ueberpruefen ob und was der Benutzer/Kunde in seinen CGI Verzeichnissen ablegt. Aber auch dafuer braucht es Erfahrung und Wissen.
Ein falsch konfigurierter Server kann aber auch Skripten in JEDEM Verzeichnis ausfuehren lassen. Man stelle sich folgendes Szenario vor:

  1. auf dem Server is anonymes FTP moeglich
  2. der Benutzer hat einen Link auf das FTP Verzeichnis gemacht (“er moechte auf die Dateien zugreifen koennen, die er upgeloadet hat”)
  3. ein BalckHat kommt drauf, schreibt sich ein irgendein Skript welches auf der Platte nach Passworten oder sonstwelchen Daten sucht
  4. Der BlackHat laedt das Skript auf den Server – es ist ueber den Link erreichbar und wegen der Fehlkonfiguration kann es auch ausgefuehrt werden.

..alles weitere ueberlasse ich Ihrer Phantasie.
Es mag zwar sein, dass derartig falsch konfigurierte Systeme unwahrscheinlich klingen. Aber sie glauben gar nicht, was man im Web alles sieht und findet…

Dem erfahrenen Webadmin moegen vielleicht meine Beispiele doch etwas trivial erscheinen. Das duerfen sie auch ruhig. Mein Ziel ist, den nicht so erfahrenen Admins zu zeigen, wie man mit trivialen Fehlern sehr viel anrichten kann und ihnen dringendst ans Herz zu legen, sich entsprechendes weitreichendes Wissen anzueignen. Das sicherste Betriebssystem mit der besten und fehlerfreisten Webserver Software auf dem schnellsten Rechner nuetzt nichts wenn aus Unwissenheit oder auch nur aus Versehen falsche Konfigurationen oder falsche Rechte gesetzt werden.
Ich moechte aber niemandem den Mut nehmen, doch selber seine(n) Server zu administrieren. Ich moechte wirklich nur betonen, dass dies – sofern der Server aus dem Internet erreichbar ist – wirklich nur dann empfehlenswert ist, wenn ein gewisses Wissen da ist. Aber troesten Sie sich – auch der erfahrenste Sys/Net/Webadmin macht manchmal Fehler…

Kommentare deaktiviert :, , Mehr...