Serverweite Konfigurationen

Das Basis Konfiguration umfasst:

  • Konfiguration der Prozessumgebung der Apache-Serverprozesse.

  • Konfiguration der geöffneten Ports.

  • Serverweit einheitliche Einstellungen.

  • Basiseinstellungen zur Sicherheit und ein einfaches Zugriffskonzept

  • Rewrite um http Requests auf https (SSL) umzuleiten, so dass nur SSL-Anfragen möglich sind

Abschluss bildet ein einfacher Test der vorgenommenen Settings.

/etc/apache2/envvars

Diese Datei ist ein Shell Skript in dem die Umgebung für apache2ctl eingestellt wird, dazu gehören auch die Benutzer- und Gruppenzugehörigkeit des Apache WEB-Server Prozesses. Bei der Installation des apache2 Pakets wurde bereits ein Benutzer und eine Gruppe hierfür eingerichtet (www-data).

export APACHE_RUN_USER=www-data
export APACHE_RUN_GROUP=www-data

/etc/apache2/ports.conf

In der Konfigration werden die Ports 80 und 443 konfiguriert auf denen der Apache Server lauschen soll.

Listen 80
<IfModule ssl_module>
    Listen 443
</IfModule>

/etc/apache2/apache2.conf

In der Konfiguration wird die Apache Server-Wide Configuration vorgenommen, dazu gehören beispielsweise ServerName, ServerAdmin, DocumentRoot (siehe Apache Core Features).

ServerName server.example.com
ServerAdmin noreply@mailinator.com
DocumentRoot /var/www/html

Der Benutzer und die Gruppe des Serverprozess werden aus den Umgebungsvariablen bezogen, die zuvor in der /etc/apache2/envvars eingerichtet wurden.

# These need to be set in /etc/apache2/envvars
User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}

Die apache2.conf Datei ist die Hauptdatei der Apache-Konfiguration, sie lädt alle weiteren Konfigurationen nach (siehe auch Apache Core Features):

IncludeOptional mods-enabled/*.load
IncludeOptional mods-enabled/*.conf
...
Include ports.conf
...
IncludeOptional conf-enabled/*.conf
IncludeOptional sites-enabled/*.conf

/etc/apache2/conf-available/security.conf

Konfiguration zur Absicherung des WEB-Servers. Abhänging vom Anwendungs- und Gefahrenkontext sind die Anforderungen und Maßnahmen zur Absicherung ganz individuell. Die in dieser Datei vorgenommenen Einstellungen relaiseren das in Abschnitt Merkmale des Setups vorgestellte Konzept:

  • alles dicht machen

Diese Konfiguration muss ggf. angepasst werden. Erste Orientierung können die Apache Security Tips geben. Die hier vorzunehmenden Einstellungen sind jedoch nur die Grundlage zur Absicherung eines Apache Servers. In Abschnitt WAF: ModSecurity wird der Aspekt der Sicherheit dann noch etwas tiefer durchdrungen.

Die Konfigurationen in dieser security.conf finden im globalen Kontext statt. Hierzu muss man wissen, dass die Apache Konfigurationen – die Direktiven genannt werden – entweder auf den gesammten Server (globaler Kontext) oder auf Sections angewendet werden können. Die Sections (Kontexte) sind z.B. Ordner, also die Pfadnamen auf Resourcen aus dem Dateisystem. Es gibt noch wesentlich mehr Kontexte, siehe Apache Kontexte (Sections).

Um bei dem Beispiel der Ordner eines Dateisystems zu bleiben: Wird beispielsweise ein Ordner im Dateisystem als Resource definiert, so erfolgt dies, indem eine Directory-Section (der Kontext) definiert wird. Die Direktieven, die in diesem Kontext gesetzt werden vererben sich auf alle Unterordner in dieser Resource. Die Vererbung erfolgt solange, bis ein Unter-Ordner kommt, für den eine eigene Directory-Section definiert wird. Dieser Kontext ist sozusagen ein Unterabschnitt des übergeordneten Ordners / dessen Kontext. Auch in diesem Kontext gelten noch die Direktieven des übergeordneten Kontext, sie können dann aber angepasst werden. So wird beispielsweise mit dem Deny from root Konzept der Root-Ordner als Kontext eingerichtet der das gesammte Dateisystem einschliesst. Unter dem Root-Ordner befinden sich bekanntlich alle Resourcen, die auf dem Dateisystem (in der Root-Umgebung) existieren, auch die WEB-Anwendungen die man auf dem Host installiert. Durch ein Deny from root schliesst man somit alle Zugriffe auf die Resourcen aus dem Dateisystem aus. Zur Installation einer WEB-Anwendung gehört, dass neben der Resource im Dateisystem noch ein Kontext im Apache konfiguriertwerden muss. In dem (Unter-) Kontext muss dann der Zugriff entsprechend der WEB-Anwendung eingeräumt werden, indem Vererbtes überschrieben und/oder angepasst werden muss.

Deny from root

Das in diesem Setup vorgenommene Sicherheits-Konzept verhindert im globalen Kontext den Zugriff auf das komplette Filesystem (von root an alles).

<Directory />

    Require all denied

    Order Deny,Allow
    Deny from all
    AllowOverride None

    Options -ExecCGI -FollowSymLinks -Includes -Indexes
    DirectoryIndex index.htm index.html

</Directory>

Mit Deny from all im Kontext des root-Ordners (<Directory />) wird der Zugriff auf jede Resource (jeden Pfad) verweigert. Die Direktive Require all denied in dem gleichen Kontext verweigert zusätzlich den Zugriff für authentifizierte Benutzer. Das erscheint hier etwas doppelt gemoppelt, macht aber Sinn, wenn man an die Vererbung (s.o.) denkt. Mit der Apache Options Direktive gilt für alle unter root stehenden Ordner:

  • Es werden keine CGI Programme ausgeführt

  • Es werden keine symbolischen Links verfolgt.

  • Die Server Side Includes (SSI) sind deaktiviert

  • Der Autoindex ist abgeschaltet (Autoindex von Directories)

Die oben gezeigten Direktieven vererben sich auf jede Resource unterhalb des root-Ordners (also faktisch auf alle Resourcen). Die WEB-Anwendungen (Sites) müssen ihre Resourcen expliziet freigeben, dazu gehört auch das Setzen der Optionen, soweit sie diese benötigen. Weiter unten wird dies beim Einrichten der Sites dann deutlich.

Request & Timeout

Vorschläge für Requests und Timeouts:

LimitRequestBody 13107200
Timeout 300
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

Hinweis

Diese Einstellungen stehen ggf. in Konkurenz mit ModSecurity. Beispielsweise hat die Direktive LimitRequestBody das Pendant SecRequestBodyLimit im WAF: ModSecurity (siehe Basis Konfiguration mod_security2.conf).

HTTP-Headers

In der security.conf werden auch die im globalen Kontext gültigen HTTP-Header Felder definiert, die dem WEB-Browser übergeben werden. Das Header Setup wurde an den Empfehlungen des OwnCloud Projekts angelehnt (lesenswert OwnCloud: Serve security related Headers by the web server). Zum Setzen der HTTP-Header ist das Apache mod_headers Modul erforderlich die Registrierung von Header Feldern erfolgt über die IANA (siehe Permanent Message Header Field Names (iana)).

<IfModule mod_headers.c>

    Header always set Strict-Transport-Security "max-age=15768000; includeSubDomains; preload"
    Header always set X-Frame-Options "SAMEORIGIN"
    # Header always set X-Robots-Tag "none"

    Header set X-Content-Type-Options "nosniff"
    Header set X-XSS-Protection "1; mode=block"

</IfModule>

Mit dem Feld X-Frame-Options: SAMEORIGIN wird der Browser angewiesen, die WEB-Seite nicht in einen fremden Frame einzubetten. Mit dem Feld X-Robots-Tag: none können Suchmaschinen angewiesen werden, die Seiten nicht zu indizieren. Will man, dass google & Co. den Content indizieren, so sollte man den dieses Feld nicht serverweit, sondern im jeweiligen Kontext setzen. Die chrome Resource ist ein Beispiel für einen Content, der i.d.R nicht von einem Robot indiziert werden soll.

<Directory /var/www/chrome>
     ...
     <IfModule mod_headers.c>
         Header always set X-Robots-Tag "none"
     </IfModule>
     ...
</Directory>

Hinweis

Die Auswertung der Header-Felder wird von den Browsern implementiert. Nicht alle WEB-Browser haben die gleichen Implementierungen oder finden zur gleichen Bewertung eines Felds. Es steht den Browesern frei ob und wie sie ein Header Feld bewerten.

SSL und Rewrite (http:// nach https://)

In der Datei /etc/apache2/sites-available/000-default.conf wird der <VirtualHost *:80> eingerichtet. Sofern mod_ssl installiert ist, werden noch die Redirects nach https:// konfiguriert (siehe Apache mod_rewrite).

<VirtualHost *:80>

    <IfModule mod_ssl.c>
     RewriteEngine   on
     RewriteRule     ^/(.*)$ https://%{SERVER_NAME}/$1 [L,R]
    </IfModule>
...
</VirtualHost>

In der Datei /etc/apache2/sites-available/default-ssl.conf wird der Security Layer (SSL) auf port 443 aktiviert und der Log-Level eingestellt:

<IfModule mod_ssl.c>
    <VirtualHost _default_:443>

        LogLevel info ssl:warn
        CustomLog ${APACHE_LOG_DIR}/access.log combined
        ...
        SSLEngine on
        ...
        SSLCertificateFile    /etc/ssl/certs/ssl-cert-snakeoil.pem
        SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
        ...
    </VirtualHost>
</IfModule>

In diesem Setup werden die selbst-signierten (snakeoil) Zertifikate verwendet (siehe auch Anmerkungen zu SSL und Zertifikaten).

/etc/apache2/conf-available/authnz_external.conf

Mit dem libapache2-mod-authnz-external Paket wurde das Apache mod_authnz_external Modul installiert. Mit diesem Modul kann die Benutzerauthentifizierung an ein externes Tool wie pwauth (github) durchgereicht werden. In der Standard Installation des libapache2-mod-authnz-external Pakets ist dass Kommando pwauth vorgesehen, das auch in diesem Setup verwendet wird.

In der authnz_external.conf werden die folgenden Direktiven gesetzt.

AddExternalAuth pwauth /usr/sbin/pwauth
SetExternalAuthMethod pwauth pipe

Das Tool pwauth (github) verwendet zur Autorisierung die Benutzer Logins und Passwörter des Systems (PAM). Zu dem pwauth gehört noch ein PAM Setup /etc/pam.d/pwauth:

auth       requisite  pam_nologin.so

# Standard Un*x authentication.
@include common-auth

# Standard Un*x account
@include common-account

Will eine Site dieses Verfahren zur Authentifizierung nutzen, so kann sie dies durch das Setzen der folgenden Direktiven.

AuthType Basic
AuthBasicProvider external
AuthName "myAuthDomain Top Secret"
AuthExternal pwauth

Mit der Apache AuthName Direktive wird die Resource einem Bereich zugeordnet. Der Bezeichner des Bereichs (realm) wird an den WEB-Client gegeben und dort im Anmeldedialog angezeigt, damit der Benutzer, das für diesen Bereich richtige Passwort eingeben kann.

Zu tun

Die Authentifizierung über pwauth (github) und authnz_external ist zwar ganz praktisch, aber damit ist nur eine Basic HTTP-Authentifizierung (wiki) möglich. Es sollte nochmal ein alternative Konzept vorgestellt werden (Schlagworte LDAP, mod_authn_file or mod_authn_dbm).

Gentleman, start your engines!

Nachdem Änderungen an der Konfiguration vorgenommen wurden, müssen diese in den Apache-Server geladen werden. Bei so substantiellen Änderungen wie sie hier vorgenommen wurden, sollte man satt nur den Reload zu machen besser einen Restart vornehmen (s.a. apachectl).

sudo -H a2ensite 000-default.conf default-ssl.conf
sudo -H a2enconf security authnz_external
sudo -H service apache2 restart

# bei kleineren Änderungen reicht ein Reload
sudo -H service apache2 reload

Zum Testen des Redirects kann auf der Komandozeile das curl Kommando genutzt werden. Das curl Kommando eignet sich eigentlich zum Download von Dateien von einem Server. Wenn man es auf verbose schaltet, dann kann man sehr schön sehen, was Client (in dem Fall curl) und Server (in dem Fall der Apache-Prozess) so an HTTP Informationen austauschen und wie die ganze Kommunikation aufgebaut wird. Folgende Optionen des curl werden verwendent:

  • --verbose gesprächige Ausgabe

  • --location folge Redirects

  • --head tausche nur die HTTP-Header aus, der Content wird ignoriert

  • --insecure keine Validierung von Zertifikaten

Der unten stehende Auszug zeigt, wie curl erst mal via http:// auf Port 80 anfragt (Anfragen habe ein > als Präfix), dann aber ein HTTP 302 Response vom Server erhält (Einkommendes hat das Präfix <). Der 302 Response verweist auf die https:// Location.

$ curl --location --verbose --head --insecure http://localhost 2>&1

* Rebuilt URL to: http://ubuntu1504/
*   Trying fd00::a00:27ff:fed5:7c85...
* Connected to ubuntu1504 (fd00::a00:27ff:fed5:7c85) port 80 (#0)
> HEAD / HTTP/1.1
> Host: ubuntu1504
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 302 Found
< Date: Thu, 11 Feb 2016 14:08:50 GMT
< Server: Apache
< Strict-Transport-Security: max-age=15768000; includeSubDomains; preload
< X-Frame-Options: SAMEORIGIN
< Location: https://ubuntu1504/
< Content-Type: text/html; charset=iso-8859-1
...

Der obige Auszug zeigt auch, dass eine Verbindung über IPv6 hergestellt wurde. Der Hostname ubuntu1504 wurde vom DNS (hier nicht zu sehen, dass passiert eine Ebene tiefer in der IP Schicht) in die IPv6 Unique Local Adresse fd00::a00:27ff:fed5:7c85 aufgelößt. Diese IPv6 Adresse wird später bei der Maskierung von Netzwerkadressen relevant werden, wenn Sites auf Basis der Host IP autorisieren (s.a. Exkursion: Netzmaske / IPv4 und IPv6).

Weiter unten in der Ausgabe von curl ist dann auch zu sehen, wie curl auf die https:// Location wechselt und seine Anfrage (Request) auf Port 443 wiederholt (Issue another request ...).

...
* Connection #0 to host ubuntu1504 left intact
* Issue another request to this URL: 'https://ubuntu1504/'
* Found bundle for host ubuntu1504: 0x55c61d8a92a0
*   Trying fd00::a00:27ff:fed5:7c85...
* Connected to ubuntu1504 (fd00::a00:27ff:fed5:7c85) port 443 (#1)
...

CHECK: Redirect –> OK!

Im weiteren Auszug (unten) ist auch zu sehen, dass TLS1.2 für die Verschlüsselung gewählt wird. Man sieht auch, dass das selbstsignierte Zertifikat, das der Server dem Client gegeben hat und das oben über die Direktive:

SSLCertificateFile    /etc/ssl/certs/ssl-cert-snakeoil.pem

gesetzt wurde, nicht verifiziert wurde, Option --insecure. Bei dieser Option SKIPPED das curl die Verfikation über einen CA (s.a. Abschnitt Anmerkungen zu SSL und Zertifikaten). Desweiteren folgen dann noch Angaben zu dem Zertifikat, z.B. das der CommonName lediglich aus dem Hostnamen besteht, dass das Zertifikat noch gültig ist und das es einen öffentlichen RSA Schlüssel besitzt.

...
* found 187 certificates in /etc/ssl/certs/ca-certificates.crt
* found 755 certificates in /etc/ssl/certs
* ALPN, offering http/1.1
* SSL connection using TLS1.2 / ECDHE_RSA_AES_128_GCM_SHA256
*     server certificate verification SKIPPED
*     server certificate status verification SKIPPED
*     common name: ubuntu1504 (matched)
*     server certificate expiration date OK
*     server certificate activation date OK
*     certificate public key: RSA
*     certificate version: #3
*     subject: CN=ubuntu1504
*     start date: Thu, 11 Feb 2016 14:04:03 GMT
*     expire date: Sun, 08 Feb 2026 14:04:03 GMT
*     issuer: CN=ubuntu1504
*     compression: NULL
* ALPN, server did not agree to a protocol
...

CHECK: DSSL Setup –> OK!

Nach den Angaben zur Verschlüsselung und dem Zertifikat ist dann im Weiteren zu sehen, wie der HTTP-Request aussieht, den curl nun abschickt (wieder an dem > zu erkennen).

...
> HEAD / HTTP/1.1
> Host: ubuntu1504
> User-Agent: curl/7.43.0
> Accept: */*scurl
...

Am Ende sieht man dann auch die Antwort (den Response) vom Server.

...
< HTTP/1.1 403 Forbidden
< Date: Thu, 11 Feb 2016 14:08:50 GMT
< Server: Apache
< Strict-Transport-Security: max-age=15768000; includeSubDomains; preload
< X-Frame-Options: SAMEORIGIN
< Content-Type: text/html; charset=iso-8859-1
...

Der Server meldet dem Client, dass der Zugriff auf die URL https://ubuntu1504/ nicht gestattet ist. Das entspricht dem Deny from root Konzept von oben. Erst wenn eine Site eingerichtet wird und diese dann Resource frei gibt, kann ein Client auf diese zugreifen.

CHECK: deny from root … OK!

An der Antwort des Servers (<) ist auch zu sehen, das die HTTP-Header-Felder Strict-Transport-Security und X-Frame-Options aus dem globalen Kontext (vergleiche HTTP-Headers) gesetzt wurden.

CHECK: HTTP Header … OK!

Wie das Beispiel zeigt, ist es mit einfachen Werkzeug wie curl bereits möglich einiges zu testen und über die Komunikation zw. Client und Server zu erfahren. Zumindest so viel, dass es ausreicht alle in diesem Abschnitt vorgenommen Einstellungen grob zu überprüfen. Oder anders formuliert, es sind nicht immer die ganz großen Werkzeuge erforderlich, das Nötigste liegt den meisten System schon anbei.