HTTPS-Absicherung & Authentifizierung via nginx Webserver

Aus FHEMWiki
Version vom 14. Juli 2016, 12:06 Uhr von Andremotz (Diskussion | Beiträge) (Seite Neuerstellung)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)

Ähnlich wie im Artikel Apache Authentication Proxy kann Fhem auch mit dem schlankeren nginx Webserver abgesichert werden. Nach diesem Artikel ist die Kommunikation zum Fhem-Server via HTTPS verschlüsselt und eine Authentifizierung nur via Benutzername und Passwort möglich. Externer Zugriff aus dem eigenen Netzwerk/Internet soll damit unterbunden werden; die Kommunikation und Authentifizierung findet verschlüsselt statt.

Voraussetzungen

Vorausgesetzt wird eine funktionierende Fhem Installation. Die dadurch erbrachten Linux Kenntnisse reichen für die Umsetzung dieses Artikels. Weiterführende Links zu Zertifikaten und dem nginx-Webserver befinden sich im Anhang des Artikels.

Ausgegangen wird von einer Fhem-Installation, die auf Port 8083 via HTTP hört. Dieser Port wird abgesichert, indem er nur noch lokal und nicht mehr über das Netzwerk erreichbar ist. Anfragen auf Port 80 (HTTP, nginx) werden weitergeleitet zum lokalen Port 443 (HTTPS, nginx), der wiederum einen Reverse Proxy auf den Port 8083 (HTTPS, fhem) einrichtet. Mit leichten Modifizierungen könnte nginx auch auf einem separaten Server betrieben werden. Die benötigten Zertifikate für die HTTPS Verschlüsselung können eigenhändig angelegt werden. Der/die autorisierten Benutzer werden in einer verschlüsselten Datei hinterlegt, die nginx für die Authentifizierung benutzt.

Getestet wurde das Setup auf einem Raspberry Pi (Raspbian - basierend auf Debian Jessie 8) und fhem 5.7. Die beschriebenen Befehle sollten sich ohne weiteres auf Ubuntu oder andere Debian-Derivate übertragen lassen. Das beschriebene Konzept lässt sich aber auf jedes Unix-Derivat anwenden.

Anpassungen: fhem-Config

In der Fhem-Konfiguration muss sichergestellt werden, dass kein Client außerhalb des Servers zugreifen kann. Dazu muss das normalerweise gesetzte Flag global von jeglicher Konfigriation entfernt werden.

Beispielkonfiguration:

attr global userattr cmdIcon devStateIcon devStateStyle genericDeviceType:ignore,switch,outlet,light$
attr global autoload_undefined_devices 1
attr global logfile ./log/fhem-%Y-%m.log
attr global modpath .
attr global motd SecurityCheck:\
\
WEB,WEBphone,WEBtablet has no basicAuth attribute.\
telnetPort has no password/globalpassword attribute.\
\
Restart FHEM for a new check if the problem is fixed,\
or set the global attribute motd to none to supress this message.\

attr global statefile ./log/fhem.save
attr global updateInBackground 1
attr global verbose 3

# define telnetPort telnet 7072 global

define WEB FHEMWEB 8083
attr WEB stylesheetPrefix dark
# attr WEB HTTPS

# define WEBhomebridge FHEMWEB 8084
# attr WEBphone stylesheetPrefix smallscreen

# define WEBtablet FHEMWEB 8085 global
# attr WEBtablet stylesheetPrefix touchpad

fhem neustarten:

 $ sudo service fhem stop && sudo service fhem start 

Installation: nginx als reverse Proxy

nginx installieren:

$ sudo apt-get install nginx 

Danach im Pfad /etc/nginx/sites-available eine neue Proxy Konfiguration anlegen:

$ sudo touch /etc/nginx/sites-available/reverse-proxy

Inhalt der Datei reverse-proxy:

server {
    listen 80;
    return 301 https://$host$request_uri;
}

server {

    listen 443;
    server_name fhempi;

    ssl_certificate           /etc/nginx/cert.crt;
    ssl_certificate_key       /etc/nginx/cert.key;

    ssl on;
    ssl_session_cache  builtin:1000  shared:SSL:10m;
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
    ssl_prefer_server_ciphers on;

    access_log            /var/log/nginx/jenkins.access.log;

    location / {

      proxy_set_header        Host $host;
      proxy_set_header        X-Real-IP $remote_addr;
      proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header        X-Forwarded-Proto $scheme;

      proxy_pass          http://localhost:8083;
      proxy_read_timeout  90;

        auth_basic "Restricted Content";
        auth_basic_user_file /etc/nginx/.htpasswd;

      # proxy_redirect      http://localhost:8083 https://localhost;
    }
  }

Mit dieser Konfiguration werden zwei Server-Instanzen auf Port 80 und Port 443 angelegt. Surft ein Browser/eine App Port 80 an, wird er umgehend zum verschlüsselten Port 443 weitergeleitet. Die Zertifikate befinden sich im lokalen Verzeichnis unter /etc/nginx und verschlüsselt wird via TLS.

User anlegen für Authentifizierung

Der Username und das verschlüsselte Passwort werden mit den folgenden Kommandos in die Datei ’’ ’/etc/nginx/.htpasswd’’’ geschrieben, das nginx in der Konfiguration für die User-Authentifizierung benutzt.

Username maxmustermann anlegen:

$ sudo sh -c "echo -n 'maxmustermann:' >> /etc/nginx/.htpasswd" 

Passwort-Prompt aufrufen:

$ sudo sh -c "openssl passwd -apr1 >> /etc/nginx/.htpasswd" 


Zertifikatserstellung

Erst durch die Zertifikate ist eine verschlüsselte Kommunikation zwischen Browser und nginx möglich Beide beschriebenen Optionen sind dabei gleichermaßen sicher. Damit allerdings nicht jedes ausgestelle Zertifikat vertraut wird, gibt es das Konzept der Certificate Authorities ('CA', näheres siehe Links). Jeder gängige Browser warnt den Benutzer vor einem Zertifikat, das von keiner Thrusted Authority ausgestellt wurde, bietet jedoch dem Benutzer die Möglichkeit, trotzdem fortzufahren. Durch die Tatsache, dass das Zertifikat selbst erstellt und signiert wird, kann diese Warnung im Browser später getrost umgangen werden.

Selbst signiertes Zertifikat erstellen:

$ sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/cert.key -out /etc/nginx/cert.crt 

Dabei werden für die Erstellung ein paar Angaben abgefragt. Wichtig ist dabei der Common Name, der identisch mit der später verwendeten Domain oder öffentliche IP-Adresse sein muss.

Country Name (2 letter code) [AU]:AT
State or Province Name (full name) [Some-State]:Vienna
Locality Name (eg, city) []:Vienna
Organization Name (eg, company) []:privat
Organizational Unit Name (eg, section) []:privat
Common Name (e.g. server FQDN or YOUR name) []:meine_domain_oder_ip
Email Address []:admin@meinedomain

nginx neustarten, um die Änderungen und das Zertifikat zu übernehmen:

$ sudo service nginx reload 

Der folgende Aufruf sollten bereits eingerichteten fhem-Server via Passwort-Abfrage und HTTPS absichern:

http://<fhemserver>

Quellen & weiterführende Links