Der 5. Teil meiner Artikelserie beschäftigt sich mit den Sicherheitseinstellungen des Apache Servers, sowie der Konfiguration des Let’s Encrypt Clients und der Einrichtung einer automatischen Zertifikatserneuerung. Die Grundkonfiguration des Apache Servers und die erste Erstellung eines Let’s Encrypt Zertifikates haben wir im 4. Teil der Artikelserie besprochen. Nun wollen wir uns die Konfiguration des Apache und des Let’s Encrypt Clients noch im Details anschauen. Zunächst betrachten wir die Konfiguration für unsere Default HTTPS Seite, die der Let’s Encrypt Client erzeugt hat.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | $ cat /etc/apache2/sites-enabled/000-default-le-ssl.conf <IfModule mod_ssl.c> <VirtualHost *:443> # The ServerName directive sets the request scheme, hostname and port that # the server uses to identify itself. This is used when creating # redirection URLs. In the context of virtual hosts, the ServerName # specifies what hostname must appear in the request's Host: header to # match this virtual host. For the default virtual host (this file) this # value is not decisive as it is used as a last resort host regardless. # However, you must set it for any further virtual host explicitly. #ServerName www.example.com ServerAdmin webmaster@mydomain.tld DocumentRoot /var/www/html # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, # error, crit, alert, emerg. # It is also possible to configure the loglevel for particular # modules, e.g. #LogLevel info ssl:warn ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined # For most configuration files from conf-available/, which are # enabled or disabled at a global level, it is possible to # include a line for only one particular virtual host. For example the # following line enables the CGI configuration for this host only # after it has been globally disabled with "a2disconf". #Include conf-available/serve-cgi-bin.conf SSLCertificateFile /etc/letsencrypt/live/mydomain.tld/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/mydomain.tld/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf ServerName mydomain.tld Header always set Strict-Transport-Security "max-age=31536000" Header always set Content-Security-Policy upgrade-insecure-requests </VirtualHost> # vim: syntax=apache ts=4 sw=4 sts=4 sr noet </IfModule> |
Wir sehen, dass der Let’s Encrypt Client das Zertifikatfile und das Schlüsselfile, sowie einen Server Namen eingetragen hat. Eine HTTPS Konfiguration ohne Servernamen ist hier sinnlos, da das Serverzertifikat für einen bestimmten Servernamen ausgestellt wurde. Ebenso wurden, wie angefordert, Header für HSTS und „Content-Security-Policy: upgrade-insecure-requests“ konfiguriert. Schliesslich hat der Let’s Encrypt Client noch eine Include Anweisung eingefügt. Die Datei /etc/letsencrypt/options-ssl-apache.conf enthält zusätzliche Anweisungen zur ssl Konfiguration.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | cat /etc/letsencrypt/options-ssl-apache.conf # Baseline setting to Include for SSL sites SSLEngine on # Intermediate configuration, tweak to your needs SSLProtocol all -SSLv2 -SSLv3 SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA SSLHonorCipherOrder on SSLCompression off SSLOptions +StrictRequire # Add vhost name to log entries: LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common #CustomLog /var/log/apache2/access.log vhost_combined #LogLevel warn #ErrorLog /var/log/apache2/error.log # Always ensure Cookies have "Secure" set (JAH 2012/1) Header edit Set-Cookie (?i)^(.*)(;\s*secure)??((\s*;)?(.*)) "$1; Secure$3$4" |
Diese Datei und weitere Konfigurationsdateien des Apache werden wir im weiteren an unsere Bedürfnisse anpassen. Auf der einen Seite wollen wir eine möglichst sichere Konfiguration, auf der anderen Seite schränken wir damit den Zugriff auf moderne Browser und Clientprogramme ein. Hier ist ein vernünftiger Kompromiss zu suchen.
Hintergrundinfomationen zu den technischen Einzelheiten findet man in der technischen Richtlinie TR-02102-2 zur Verwendung von Transport Layer Security (TLS) des BSI, der RFC 7525: Recommendations for Secure Use of Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS) der Internet Engineering Task Force IETF und in den Guidelines for the Selection, Configuration, and Use of Transport Layer Security (TLS) Implementations des NIST.
Zur Zeit existieren mehrere Webseiten, auf denen man die Webserver-Konfiguration des eigenen Server scannen lassen kann. Wir werden uns die Ergebnisse dreier Testseiten anschauen. Dies sind der SSL Server Test der Qualys SSL Labs, der Free SSL Server Test der High-Tech Bridge SA, sowie das Mozilla Observatory.
Als erstes schauen wir uns die Ergebnisse unserer Default Konfiguration auf den drei Testseiten an, zunächst auf dem SSL Server Test der Qualys SSL Labs. Auf der Seite tragen wir die URL unseres Servers ein, setzen gegebenenfalls das Häkchen bei „Do not show the results on the boards“ und klicken den Submit Button. Der Test dauert mehr als eine Minute. Wenn der Testdurchlauf beendet ist gibt er uns einen detailierten Bericht zu unserem Webserver.
Das sieht ja schon mal gut aus, wir bekommen ein A+ Overall Rating, Details schauen wir uns später an. Zunächst interessiert uns das Ergebnis der anderen beiden Testseiten. Zunächst schauen wir uns das Ergebnis des Free SSL Server Test der High-Tech Bridge SA an. Auf dieser Seite geben wir ebenfalls unsere Domain ein, setzen gegebenenfalls das Häkchen bei „Do not display test results in statistics“ und klicken dann auf das blaue Dreieck im Domainnamenfeld. Der Test dauert ebenfalls etwa eine Minute und auch hier erhalten wir einen ausführlichen Bericht, der allerdings etwas andere Schwerpunkte setzt.
Hier erhalten wir FINAL GRADE A und wir können den Bericht als PDF herunterladen. Dokumentation zu den durchgeführten Tests finden wir unter den beiden Links im Kasten „SSL/TLS Security Test by High-Tech Bridge„. Details des Berichtes schauen wir uns später an.
Abschliessend lassen wir unseren Server durch das Mozilla Observatory scannen. Das Ergebnis ist etwas überraschend, aber auch hier sind die Schwerpunkte anders gesetzt.
Hier erhalten wir nur ein C- und nur 45 von 100 Punkten. Wenn wir weiter nach unten scrollen, finden wir den folgenden Abschnitt Suggestions:
Ein Click auf die Links Mozilla „Modern“ TLS configuration oder Mozilla „intermediate“ TLS configuration bringt uns auf der Mozilla wiki Security/Server Side TLS Seite zu den entsprechenden Tags. Wenn wir auf die Links „Wan’t the detailed technical nitty-gritty?“ klicken, werden Informationen zum Anpassen unserer Konfiguration eingeblendet, siehe folgende Abbildung.
Hier werden Vorschläge zu Änderungen an unserer Konfiguration gemacht. Unten im Bild gibt es eine Button Teleport me to Mozilla’s configuration generator!. Wenn wir diesen Button anklicken, landen wir beim Mozilla SSL Configuration Generator. Dort wählen wir Apache als unseren Webserver und unsere Version 2.4.18 aus. Dann geben wir noch unsere openssl Version 1.0.2g ein und wählen das „Modern“ Konfigurationsprofil aus. Damit erhalten wir eine Beispiel-SSL-Konfiguration für unseren Apache Webserver, siehe folgende Abbildung.
Diese Beispiel-Konfiguration, sowie die Empfehlungen auf den übrigen Testseiten, wollen wir zur Basis unserer Apache-SSL-Konfiguration machen. Zunächst erläutere ich die Änderungen an unserer Konfiguration, danach werden wir uns das Ergebnis auf den Testseiten anschauen.
Als erstes wollen wir OCSP Stapling konfigurieren. Dies sind die Zeilen aus der Beispiel-Konfiguration:
1 2 3 4 5 | # OCSP Stapling, only in httpd 2.3.3 and later SSLUseStapling on SSLStaplingResponderTimeout 5 SSLStaplingReturnResponderErrors off SSLStaplingCache shmcb:/var/run/ocsp(128000) |
Für unsere Zwecke werden wir die Konfiguration aufteilen. Ich möchte die SSLStapling Optionen für den gesamten Apache-Server konfigurieren und die Aktivierung des Staplings in den einzelnen vhosts vornehmen.
Zunächst legen wir im Apache Konfigurationsverzeichnis ein neues Unterverzeichnis an.
1 | mkdir /etc/apache2/misc |
Dort erzeugen wir eine Datei options-OCSPStabling-apache.conf mit dem folgenden Inhalt:
1 2 3 4 5 | $ cat /etc/apache2/misc/options-OCSPStabling-apache.conf # Configure OCSP Stapling options. Enable OCSP Stapling in the vhost. SSLStaplingCache shmcb:${APACHE_RUN_DIR}/ocsp(128000) SSLStaplingResponderTimeout 5 SSLStaplingReturnResponderErrors off |
Per Include Anweisung binden wir dann diese Anweisungen in die Konfiguration des SSL Moduls /etc/apache2/mods-available/ssl.conf ein. Hier ein Auszug der geänderten Datei:
1 2 3 4 5 6 7 8 9 10 | # Whether to forbid non-SNI clients to access name based virtual hosts. # Default: Off #SSLStrictSNIVHostCheck On # Configure OCSP Stabling Include /etc/apache2/misc/options-OCSPStabling-apache.conf </IfModule> # vim: syntax=apache ts=4 sw=4 sts=4 sr noet |
Zusätzlich müssen wir in unserer vhost Konfiguration, das OCSP Stapling aktivieren. Dies erreichen wir durch hinzufügen der folgenden Zeile zur vhost Konfiguration.
1 | SSLUseStapling on |
Ich habe eine entsprechenden Eintrag vor der SSLCertificateFile Anweisung eingefügt, siehe folgenden Auszug aus unserer vhost Konfiguration /etc/apache2/sites-enabled/000-default-le-ssl.conf:
1 2 3 4 5 6 7 | # after it has been globally disabled with "a2disconf". #Include conf-available/serve-cgi-bin.conf # OCSP Stapling, only in httpd 2.3.3 and later. Stapling options configured in ssl.conf SSLUseStapling on SSLCertificateFile /etc/letsencrypt/live/mydomain.tld/fullchain.pem |
Nun wenden wir uns nochmal unserer SSL-Konfiguration zu. Im folgenden Listing zeige ich meine aktuelle Konfiguration und werde sie im Anschluss erläutern.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | cat /etc/letsencrypt/options-ssl-apache.conf # Baseline setting to Include for SSL sites SSLEngine on # Let's Encrypt Defaults # Intermediate configuration, tweak to your needs # SSLProtocol all -SSLv2 -SSLv3 # SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA # Mozilla modern profile # SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 # SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 # Mozilla intermediate profile # SSLProtocol all -SSLv3 # SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS # My profile SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:!DES:!DSS SSLHonorCipherOrder on SSLCompression off # Bump up the strength of the ECDHE key exchange. According to blog.joelj.org SSLOpenSSLConfCmd ECDHParameters secp384r1 SSLOpenSSLConfCmd Curves secp384r1 # Mozilla recommendation SSLSessionTickets off SSLOptions +StrictRequire # Add vhost name to log entries: LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common #CustomLog /var/log/apache2/access.log vhost_combined #LogLevel warn #ErrorLog /var/log/apache2/error.log # Always ensure Cookies have "Secure" set (JAH 2012/1) Header edit Set-Cookie (?i)^(.*)(;\s*secure)??((\s*;)?(.*)) "$1; Secure$3$4" |
Wie einfach zu sehen ist, habe ich verschiedene Konfigurationen für SSLProtocol und SSLCipherSuite eingetragen und die von mir nicht benutzten lediglich auskommentiert. Dies gestattet es später schnell zu einer anderen Konfiguration zu wechseln.
Ich habe mich hier für eine relativ strikte Konfiguration enzschieden, die auch eine Reihe älterer Clients aussperrt. Aber dies ist durchaus in meinem Sinne, denn ich gehe davon aus, dass derjenige der noch entsprechend alte Clients einsetzt nicht an diesen Sicherheits-Themen interessiert ist.
Das einzige SSLProtokoll das meine Konfiguration momentan unterstützt ist TLSv1.2. Wenn TLSv1.3 veröffentlicht ist, würde es ebenfalls unterstützt.
Die gewählten CipherSuites unterstützen alle PFS (Perfect Forward Secrecy). Die unterstützen Schlüsselaustauschverfahren sind ECDHE und DHE, zur Hintergrundinfomation siehe auch Diffie–Hellman key exchange, Elliptic curve Diffie–Hellman auf wikipedia.org und SSL/TLS & Perfect Forward Secrecy von Vincent Bernat.
Zur Authentifizierung wird unser RSA-Zertifikat mit 4096 bit Schlüssellänge benutzt. Let’s Encrypt unterstützt inzwischen auch die Benutzung von ECDSA-Zertifikaten, der Certbot aber noch nicht. Bis dies soweit ist, wird sicher noch einige Zeit ins Land gehen, siehe ECDSA subject key support #2660. Einzelheiten zu ECDSA sind ebenfalls auf wikipedia.org zu finden.
Zur Verschlüsselung verwenden die eingesetzten Suiten AES mit 256 oder 128 bit Schlüssellänge, mit 128 Bit Blocklänge im GCM oder CBC Modus. Der GCM Modus ist der Bevorzugte, siehe hierzu auch Galois/Counter Mode auf wikipedia.org. Als Message Authentication Code (MAC) kommt SHA384 oder alternativ SHA256, sowie SHA1 zum Einsatz. Zum Hintergrund von SHA siehe den wikipedia Artikel SHA-2.
Die Varianten mit Streamcipher ChaCha20 und MAC Poly1305 sind zwar konfiguriert, aber unser openssl 1.0.2g beherrscht diese noch nicht. Dazu ist openssl 1.1.0 erforderlich. Details zu ChaCha20 und Poly1305 sind ebenfalls auf wikipedai.org zu finden.
Die beiden SSLOpenSSLConfCmd Anweisungen setzen die ECDH-Parameter auf 384 bit bzw. wählen die Kurve secp384r1 aus.
Das Ergebnisse dieser Einstellungen auf den verschiedenen Testseiten wollen wir uns nun nochmals im Detail anschauen, zunächst für den SSL Server Test der Qualys SSL Labs.
Wie wir sehen erhalten wir wieder ein Overall Rating A+, einziger Test der nicht die volle Punktzahl erhalten hat ist der Test für die Cipher Strength. Dies erklärt sich dadurch, dass die Punktzahl für die stärkste Verschlüsselung, in unserem Falle AES mit 256 bit (100/100), und die Punktzahl für die schwächste Verschlüsselung, hier AES mit 128 bit (80/100), addiert und durch zwei dividiert wird. Details zur Bewertung findet man im SSL Server Rating Guide.
Nun wollen wir uns aber auch die Details des Tests näher anschauen. IN der folgenden Abbildung sehen wir Details zum Server Schlüssel und zur Zertifikatskette.
Die nächste Abbildung zeigt uns Details zu den konfigurierten Protokollen und Cipher Suiten.
Besonders interessant ist ein Blick auf die folgende Handshake Simulation.
In rot sehen wir, die nicht erfolgreichen Verbindungsversuche. Dies betrifft vor allem, alte Windows Versionen mit altem Internet Explorer, alte Android Versionen, sowie Java 6 und Java 7. Wenn wir Java überhaupt nicht unterstützen müssen, können wir die Cipher Suiten mit 128 bit AES-Verschlüsselung entfernen und somit volle Punktzahl erreichen. Der einzige der gezeigten Clients, der 128-bit AES Verschlüsselung anfordert, ist Java 8.
Zum Schluss schauen wir uns noch die Protokol Details an.
Das sieht alles in allem gut aus. Public Key Pinning (HPKP) wollen wir momentan nicht implementieren.
Damit wenden wir uns dem Free SSL Server Test der High-Tech Bridge SA zu, beginnend mit der Summary.
Auch hier erhalten wir wieder einen Final Grade von A+. Auch hier werfen wir noch eine kurzen Blick auf die Details.
Hier sehen wir, dass unsere Konfiguration nicht den Anforderungen der NIST Guidelines entspricht. Es fehlen uns das TLSv1.1 Protokol, sowie drei Cipher, die von der NIST vorgesehen sind, dies ist aber so gewollt.
Die folgenden beiden Abbildungen zeigen die Übereinstimmung mit den PCI DSS Anforderungen, bzw. den „Industry Best-Practices“.
Das sieht Gut aus.
Zuletzt sehen wir den „Web Server Security Overview“.
Hier sehen wir, dass wir bei der Konfiguration der HTTP Header noch einiges zu tun haben. Dem wollen wir uns aber erst später zuwenden. Zunächst wollen wir noch einen Blick auf die Ergebnisse des Mozilla Observatorys werfen.
Wenig überraschend erhalten wir immer noch nur ein C-, da wir die HTTP Header noch nicht richtig konfiguriert haben. Dies wollen wir nun nachholen.
Zunächst nehmen wir ein paar Änderungen an der Datei /etc/apache2/conf-enabled/security.conf vor. Als erstes ändern wir den HTTP response Header. Dieser wird gleich im zweiten Block der Datei mit der ServerTokens Directive gesetzt. In der Ubuntu Standardkonfiguration ist hier ServerTokens OS gesetzt. Diese Zeile kommentieren wir aus und fügen eine neue Zeile ServerTokens Prod ein. Der gesamt Block in der Datei sieht dan aus wie folgt:
1 2 3 4 5 6 7 8 9 10 11 | # # ServerTokens # This directive configures what you return as the Server HTTP response # Header. The default is 'Full' which sends information about the OS-Type # and compiled in modules. # Set to one of: Full | OS | Minimal | Minor | Major | Prod # where Full conveys the most information, and Prod the least. #ServerTokens Minimal #ServerTokens OS #ServerTokens Full ServerTokens Prod |
Am Ende der Datei finden wir die beiden auskommentierten Anweisungen #Header set X-Content-Type-Options: "nosniff" und #Header set X-Frame-Options: "sameorigin". Bei beiden entfernen wir das Komentarzeichen. Das Ende der Datei /etc/apache2/conf-enabled/security.conf sieht dan wie folgt aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # # Setting this header will prevent MSIE from interpreting files as something # else than declared by the content type in the HTTP headers. # Requires mod_headers to be enabled. # Header set X-Content-Type-Options: "nosniff" # # Setting this header will prevent other sites from embedding pages from this # site as frames. This defends against clickjacking attacks. # Requires mod_headers to be enabled. # Header set X-Frame-Options: "sameorigin" # vim: syntax=apache ts=4 sw=4 sts=4 sr noet |
Abschliessend fügen wir noch zwei Anweisungen in unsere virtual host Konfiguration ein. Am Ende des VirtualHost Blocks in der Datei /etc/apache2/sites-available/000-default-le-ssl.conf fügen wir die folgenden beiden Zeilen ein:
1 2 | Header always set X-XSS-Protection "1; mode=block" Header always set Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self'" |
Einen netten Hintergrundartikel zum Thema XSS und Content Security Policy von Hendrik Brummermann findet bei Heise, XSS-Bremse Content Security Policy. Der Artikel ist nicht mehr ganz aktuell (die modernen Browser verstehen inzwischen die Content-Security-Policy Anweisungen), gibt aber einen guten Überblick, über die Zusammenhänge. Die Content Security Policy Reference findet man hier.
Nun starten wir den Apache nochmals neu, systemctl restart apache2 und schauen uns anschliessend die Ergebnisse des Mozilla Observatorys an.
Jetzt erhalten wir auch hier ein A+, 100 von 100 Punkten. Wir können uns auch hier noch die Details anschauen. Interessant ist der Abschnitt „Third-party Scan Results“.
HSTS Preload wird von unserer Konfiguration nicht unterstützt, deshalb das X bei hstspreload.appspot.com. Das einzige was bei securityheaders.io angemahnt wird, ist das Fehlen von HPKP (Public Key Pinning). Ich habe momentan allerdings auch nicht vor dieses zu implementieren.
Mit dieser Konfiguration bin ich nun sehr zufrieden. Es bleibt jetzt nur noch eine automatische Erneuerung der Zertifikate einzurichten. Zunächst legen wir eine Konfigurationdatei für Let’s Enrypt im Verzeichnis /etc/letsencrypt an. Dazu kopieren wir die Beispielkonfiguration /usr/share/doc/python-letsencrypt-doc/examples/cli.ini in das Verzeichnis /etc/letsencrypt und passen sie an unsere Bedürfnisse an.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # This is an example of the kind of things you can do in a configuration file. # All flags used by the client can be configured here. Run Let's Encrypt with # "--help" to learn more about the available options. # Use a 4096 bit RSA key instead of 2048 rsa-key-size = 4096 # Uncomment and update to register with the specified e-mail address email = whoever@whereever.de # Uncomment and update to generate certificates for the specified # domains. # domains = example.com, www.example.com # Uncomment to expand the cert with additional names # expand = True # Uncomment to use a text interface instead of ncurses # text = True # Uncomment to use the standalone authenticator on port 443 # authenticator = standalone # standalone-supported-challenges = tls-sni-01 # Uncomment to use the webroot authenticator. Replace webroot-path with the # path to the public_html / webroot folder being served by your web server. # authenticator = webroot # webroot-path = /usr/share/nginx/html |
Ich habe hier nur meine E-Mail Adresse und die Schlüssellänge eingetragen, alles andere steuere ich über Kommandozeilenparameter.
Dann testen wir die automatische Zertifikatserneuerung auf der Kommandozeile.
1 | letsencrypt renew -c /etc/letsencrypt/cli.ini --agree-tos --dry-run |
Wir erhalten die folgende Ausgabe:
1 2 3 4 5 6 7 8 | Processing /etc/letsencrypt/renewal/public1.emrich-ebersheim.de.conf ** DRY RUN: simulating 'letsencrypt renew' close to cert expiry ** (The test certificates below have not been saved.) Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/public1.emrich-ebersheim.de/fullchain.pem (success) ** DRY RUN: simulating 'letsencrypt renew' close to cert expiry ** (The test certificates above have not been saved.) |
Danach wechseln wir in unser Home Verzeichnis und legen dort ein Verzeichnis „bin“ an.
1 2 | cd mkdir bin |
In diesem Verzeichnis erstellen wir ein Script letsencrypt-updatecerts.sh mit dem folgenden Inhalt.
1 2 3 4 | #!/bin/bash cd /root letsencrypt renew -c /etc/letsencrypt/cli.ini --agree-tos |
Anschließend setzen wir noch die Permissions.
1 | chmod 700 /root/bin/letsencrypt-updatecerts.sh |
Jetzt führen wir noch einen Testlauf unseres Scripts durch.
1 2 3 4 5 6 | $ /root/bin/letsencrypt-updatecerts.sh Processing /etc/letsencrypt/renewal/public1.emrich-ebersheim.de.conf The following certs are not due for renewal yet: /etc/letsencrypt/live/public1.emrich-ebersheim.de/fullchain.pem (skipped) No renewals were attempted. |
Das sieht gut aus. Unser Zertifikat ist noch nicht zur Erneuerung fällig. Abschließend legen wir einen crontab Eintrag an, der das Script einmal am Tag um 1:33 Uhr ausführt.
Am einfachsten rufen wir dazu crontab -e auf und ergänzen am Ende der Datei die folgende Zeile:
1 | 33 1 * * * /root/bin/letsencrypt-updatecerts.sh |
Dann speichern wir ab und überprüfen mit crontab -l , ob der Eintrag korrekt ist. Die Meldungen, die das Script bei der Ausführung ausgibt, werden an den Benutzer, in diesem Falle „root“, gemailt. Dadurch haben wir die Kontrolle über auftretende Fehler.
Es gibt momentan noch einen Schönheitsfehler. Da der Mailserver noch nicht richtig konfiguriert ist, landen die Mails des cron jobs im lokalen Postfach für nobody. Das kann für den produktiven Betrieb so nicht bleiben. Da meine Domain, zu der unser Server gehört, auf einem Hostingvertrag ebenfalls bei 1&1 läuft und die E-Mails dort gehostet werden, ist die Lösung des Problems denkbar einfach. Wir müssen nur Postfix richtig für ausgehende Mail konfigurieren. Postfix ist als Mailserver vorkonfiguriert und läuft bereits.
Als erstes fügen wir noch einen Eintrag für unseren Server in der Datei /etc/hosts an.
1 | 87.106.152.141 public1.emrich-ebersheim.de public1 |
Danach konfigurieren wir Postfix neu.
1 | dpkg-reconfigure postfix |
Die folgenden Abbildungen zeigen den Ablauf der Konfiguration. Der erste Dialog gibt uns einige Informationen zu den möglichen Server Konfigurations Typen.
Auf der nächsten Seite wählen die Konfiguration Satellite system.
Auf der nächsten Seite geben wir den voll qualifizierten Namen unseres Server als Sytem Mail Name an.
Auf der folgenden Seite tragen wir den Empfänger der System Mails ein. An diese Adresse werden Mails an root oder postmaster weitergeleitet.
Den Eintrag für den SMTP Relay Host lassen wir leer, damit sollte der MX-Record im DNS ausgewertet werden und dazu führen, dass der 1&1 Mailexchanger als Relayhost fungiert.
Auf der nächsten Seite wird angegeben, für welche Netzwerke unser Server Mails weiterleiten soll. Diesen Eintrag übernehmen wir unverändert nur für die lokalen Netzwerkadressen.
Auf der folgenden Seite konfigurieren wir synchrone Updates für die Mailqueue.
Auch den Eintrag auf der nächsten Seite übernehmen wir unverändert. Er legt fest für welche Domänen sich unser Server als Empfänger betrachtet.
Die nächste Dialogseite legt die maximale Postfachgröße fest. Wir belassen den Wert bei Null, das bedeutet unbegrenzte Mailboxgrösse.
Auch den nächsten Eintrag belassen wir bei der Standardeinstellung.
Für die lokale Auslieferung der Mail benutzen wir procmail. Wir müssen in diesem Fall daran denken nach dem Abschluss der Postfix Konfiguration ein entsprechendes Alias für root in der Datei /etc/aliases anzulegen.
Zuletzt setzen wir ipv4 als zu benutzendes Internet Protokol, öffentliche ipv6 Adressen haben wir ja nicht.
Nachdem wir den Konfigurationsdialog abgeschlossen haben, bekommen wir noch folgende Ausgabe:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | setting synchronous mail queue updates: true setting myorigin setting destinations: $myhostname, localhost.localdomain, localhost.localdomain, , localhost setting relayhost: setting mynetworks: 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 setting mailbox_command setting mailbox_size_limit: 0 setting recipient_delimiter: + setting inet_interfaces: loopback-only setting inet_protocols: ipv4 WARNING: /etc/aliases exists, but does not have a root alias. Postfix is now set up with the changes above. If you need to make changes, edit /etc/postfix/main.cf (and others) as needed. To view Postfix configuration values, see postconf(1). After modifying main.cf, be sure to run '/etc/init.d/postfix reload'. Running newaliases |
Hier erhalten wir nochmals die Erinnerung, dass wir noch ein root alias einrichten müssen. Dazu ergänzen wir in der Datei /etc/aliases eine Weiterleitungszeile folgender Form.
1 | root: me@mydomain.tld |
Bitte eine sinnvolle E-Mail-Adresse eintragen, damit die Mails bei Euch ankommen. Diese Änderung muss noch in die aliases Database übernommen werden. Dazu müssen wir das Kommando newaliases ausführen.
Beim Testen musste ich feststellen, dass meine ausgehende Mail vom 1&1 Mailexchanger nicht akzeptiert wird. Doch ein Blick in die Datei /etc/postfix/main.cf zeigt sehr schnell wo das Problem liegt. Verursacher ist die folgende Zeile:
1 | myhostname = localhost.localdomain |
Dies ändern wir von Hand mit einem Editor.
1 | myhostname = public1.emrich-ebersheim.de |
Anschliessend starten wir Postfix neu.
1 | systemctl restart postfix |
Jetzt können wir testen, ob ausgehende Mail funktioniert.
1 2 3 | mail -s Test root@localhost Das ist ein Test. Cc: |
Der Mailtext wird mit der Eingabe von Strg+D auf einer neuen Zeile beendet. Daraufhin wird die Möglichkeit angeboten eine CC Adresse anzugeben. Hier drücken wir einfach Return. Die Testmail sollte dann an der oben angegebenen E-Mail-Adresse ankommen.
Somit haben wir nun die Konfiguration eines Webservers mit Let’s Encrypt Zertifikaten abgeschlossen. Zum Abschluss machen wir noch einen Backup und nehmen dabei die Postfix Konfiguration ins Backup mit auf.
1 2 | cd /opt/1UND1EU/bin/ ./ClientTool control.selection.modify -datasource FileSystem -include /etc/postfix |
1 | ./ClientTool control.backup.start -datasource FileSystem |
Im 6. Teil meiner Artikelserie werden wir dann auch Postfix für die Benutzung unserer Let’s Encrypt Zertifikate konfigurieren.