en / de
Expertisen
Methoden
Dienstleistungen
Referenzen
Jobs & Karriere
Firma
Technologie-Trends TechCast WebCast TechBlog News Events Academy

gRPC Tutorial Teil 4: HTTP/2 über HTTPS

gRPC benutzt HTTP/2, welches 2015 veröffentlicht wurde und binäre Kommunikation unterstützt. Moderne Browser unterstützen HTTP/2 ausschliesslich über eine gesicherte Verbindung. Ein gRPC-Client kann dagegen problemlos über eine ungesicherte Verbindung mit einem gRPC-Server kommunizieren. Für Autorisierungstechniken wie z.B. JWT Bearer Tokens (siehe Blog über JWT Client Credentials) muss die Verbindung zwingend gesichert sein. In diesem Blog wird demonstriert, wie man den Kestrel-Server für eine gesicherter Verbindung konfiguriert. Obwohl dieser Blog als Grundlage für einen späteren gRPC-Blog dient, funktioniert das Absichern genau gleich wie für eine REST-Schnittstelle oder eine normale Internetseite.

Basisdefinitionen

HTTP (Hypertext Transfer Protocol) ist ein Protokoll, das von Clients (z. B. Webbrowsern) verwendet wird, um Ressourcen von Servern (z. B. Webservern) anzufordern.

HTTPS ist eine Methode zum Verschlüsseln von HTTP. Grundsätzlich werden HTTP-Nachrichten in einem verschlüsselten Format unter Verwendung von SSL / TLS verpackt.

Eine gesicherte Verbindung läuft heutzutage über TLS. Zur Unterstützung älterer Browser bieten die meisten Server auch SSL an. Leider wird oft immer noch SSL gesagt, wenn eigentlich TLS gemeint ist (z.B. badssl.com).

Verschlüsseln und signieren

Um den Datenverkehr zu verschlüsseln, braucht es einen Schlüssel, welcher den Klartext in einen Geheimtext (Chiffrat) umwandeln kann und wieder zurück. Es gibt zwei grundlegende Verfahren sowie eine Kombination von beiden.

Bei der symmetrischen Verschlüsselung wird derselbe Schlüssel verwendet, um Botschaften zu verschlüsseln und auch wieder zu entschlüsseln. Der Schlüssel muss also sowohl dem Sender als auch dem Empfänger bekannt sein.

Bei der asymmetrischen Verschlüsselung, oder Public-Key-Verschlüsselungsverfahren, gibt es einen öffentlichen und einen privaten Schlüssel.

Daten, die mit dem öffentlichen Schlüssel verschlüsselt wurden, können nur mit dem dazugehörigen privaten Schlüssel entschlüsselt werden.

Verschlüsseln und Signieren mit Public-/Private Key pair

Verschlüsseln und Signieren mit Public-/Private Key pair

Quelle: https://de.wikipedia.org/wiki/asymmetrisches_kryptosystem

Das gleiche Schlüsselpaar wird zum Signieren verwendet. Zum Erstellen einer Signatur wird ein Hashwert aus der zu verschickenden Nachricht gebildet und mit dem privaten Schlüssel signiert. Nachricht und Signatur werden dann zum Empfänger geschickt. Zum Verifizieren der Signatur wird die empfangene Signatur des Hashwertes mit dem öffentlichen Schlüssel geprüft. Ist die Verifizierung erfolgreich, kann davon ausgegangen werden, dass die Nachricht vom Besitzer des privaten Schlüssels stammt und dass die Nachricht bei der Übertragung nicht (zufällig oder absichtlich) manipuliert wurde.

Ein Nachteil der asymmetrischen Verschlüsselung ist der hohe Aufwand für die Ver- und Entschlüsselung, was sich deutlich auf die Geschwindigkeit auswirkt.

Bei der hybriden Verschlüsselung wird mit der asymmetrischen Verschlüsselung die Authentizität des Servers (und optional Clients) überprüft und ein symmetrischer Schlüssel zur Verschlüsselung der nachfolgenden Daten übertragen. Dieser Ablauf findet beim Aufsetzen einer HTTPS-Verbindung statt, auch TLS Handshake genannt.

Das Aufsetzen einer HTTPS-Verbindung

Bevor eine gesicherte Verbindung zustande kommt, wird zwischen Client und Server verhandelt.

Noser Engineering - gRPC - TLS Handshake

TLS Handshake

Quelle: https://www.ibm.com/support

  1. Der Client sendet eine «client hello»-Nachricht, in der u.a. die TLS-Version und die vom Client unterstützten Verschlüsselungsalgorithmen (CipherSuites) aufgelistet sind.
  2. Der Server antwortet mit einer «server hello»-Nachricht mit der gewählten CipherSuite, der Sitzungs-ID und dem Server-Zertifikat.
    Optional: Wenn für den Server ein digitales Zertifikat für die Clientauthentifizierung erforderlich ist, sendet der Server eine Clientzertifikatsanforderung (siehe nächsten Blog über Client-Zertifikat Authentifizierung).
  3. Der Client überprüft das digitale Zertifikat des Servers. Das Hauptziel ist es, sicherzustellen, dass der Server tatsächlich der Server ist, für den ihn der Client hält. Dieser Vorgang ist kompliziert und sprengt den Rahmen dieses Blogs.
  4. Der Client sendet die zufällige Bytefolge, die es sowohl dem Client als auch dem Server ermöglicht, den geheimen Schlüssel zu berechnen, der für die Verschlüsselung der nachfolgenden Nachrichtendaten verwendet werden soll. Die zufällige Bytefolge selbst wird mit dem öffentlichen Schlüssel vom Server-Zertifikat verschlüsselt.
  5. Optional: Wenn der Server eine Clientzertifikatsanforderung gesendet hat, sendet der Client eine zufällige Bytefolge, die mit dem privaten Schlüssel des Clients verschlüsselt wird, zusammen mit dem Client-Zertifikat des Clients.
  6. Optional: Der Server überprüft das Client-Zertifikat.
  7. Der Client sendet dem Server eine «Finished»-Nachricht.
  8. Der Server sendet dem Client eine «Finished»-Nachricht.
  9. Für die Dauer der TLS-Sitzung können jetzt Server und Client Nachrichten austauschen, die symmetrisch mit dem geheimen Schlüssel für gemeinsame Nutzung verschlüsselt sind.

 

Root- und Server-Zertifikat

Um die HTTPS-Verbindung aufsetzen zu können, braucht es ein Server-Zertifikat. Das Server-Zertifikat befindet sich am Ende der Zertifizierungskette. Am Anfang der Kette befindet sich das Root-Zertifikat, welches verwendet wird, um die Echtheit des Zertifikates und damit auch die Authentizität des Servers zu beweisen.

Ein digitales Client-Zertifikat ist im Grunde eine Datei, die mit einem Passwort geschützt und in eine Client-Anwendung geladen wird (normalerweise als PKCS12-Datei mit der Erweiterung ‘.p12’ oder ‘.pfx’, die Datei kann mit z.B. OpenSSL konvertiert werden in einer .crt/.cer und .key Datei. Letztere Datei enthält den private Key).

Ein digitales Zertifikat enthält relevante Informationen wie eine digitale Signatur, Ablaufdatum, Name des Issuers, Name der CA (Certificate Authority), Sperrstatus (revocation), SSL/TLS-Versionsnummer, Seriennummer und möglicherweise weitere Informationen, die alle nach dem X.509-Standard strukturiert sind.

Selbstsignierte Zertifikate erstellen

Normalerweise werden Zertifikaten von Zertifizierungsstellen (‘certificate authority’ oder ‘certification authority’, kurz CA) ausgestellt (z.B. Verisign, Thawte, etc.). Für unser Beispiel werden wir selber die Zertifikate generieren. Es gibt verschiedene Wege selber Zertifikate zu generieren: Powershell, Online Tools, OpenSSL etc. In diesem Beitrag wird OpenSSL verwendet.

OpenSSL installieren

Die binären Dateien des OpenSSL Tools stehen als ZIP-Datei zur Verfügung auf ‘https://sourceforge.net/projects/openssl‘ oder als Installer auf ‘https://slproweb.com/products/Win32OpenSSL.html‘. Dazu die letzte Version des Installers ‘Win64OpenSSL_Light-1_1_0L.exe’ (oder höher) herunterladen und den Installer ausführen. Wichtig ist, dass ‘openssl.exe’ und ‘openssl.cnf’ sich nach der Installation im Verzeichnis ‘C:\OpenSSL-Win64\bin’ befinden.

Zertifikate generieren

Im Beispiel gibt es einen Unterordner ‘Certs’ in dem alle OpenSSL Tool Input- und Output-Dateien gespeichert werden.

Die Inhalte des Zertifikatfeldes ‘Enhanced Key Usage’ müssen für das OpenSSL Tool in einer externen Datei definiert werden. In diesem Verzeichnis eine Textdatei ‘openssl-ext.cnf’ mit folgendem Inhalt erstellen:

[server_ssl]
extendedKeyUsage = serverAuth

Eine zweite Datei namens ‘create_certs.cmd’ mit folgendem Inhalt erstellen:

set OPENSSL_CONF=c:\OpenSSL-Win64\bin\openssl.cfg   

echo Generate CA key:
c:\OpenSSL-Win64\bin\openssl genrsa -passout pass:P@ssw0rd -des3 -out root.key 4096

echo Generate CA certificate:
c:\OpenSSL-Win64\bin\openssl req -passin pass:P@ssw0rd -new -x509 -days 3650 -key root.key -out root.crt -subj "/C=CH/ST=LU/L=Root D4/O=Noser Engineering AG/OU=www.noser.com/CN=Noser RpcWithCertificates Root"

echo Generate server key:
c:\OpenSSL-Win64\bin\openssl genrsa -passout pass:P@ssw0rd -des3 -out server.key 4096

echo Generate server signing request:
c:\OpenSSL-Win64\bin\openssl req -passin pass:P@ssw0rd -new -key server.key -out server.csr -subj "/C=CH/ST=LU/L=Root D4/O=Noser Engineering AG/OU=www.noser.com/CN=localhost"

echo Self-sign server certificate:
c:\OpenSSL-Win64\bin\openssl x509 -req -passin pass:P@ssw0rd -days 3650 -extensions server_ssl -extfile openssl-ext.cnf  -in server.csr -CA root.crt -CAkey root.key -set_serial 01 -out server.crt

echo Remove passphrase from server key:
c:\OpenSSL-Win64\bin\openssl rsa -passin pass:P@ssw0rd -in server.key -out server.key

c:\OpenSSL-Win64\bin\openssl pkcs12 -export -in root.crt -inkey root.key -out root.pfx -passout pass:P@ssw0rd -passin pass:P@ssw0rd -name "Noser Engineering self-signed root cert"

c:\OpenSSL-Win64\bin\openssl pkcs12 -export -in server.crt -inkey server.key -out server.pfx -passout pass:P@ssw0rd -name "Noser Engineering self-signed server cert"

pause

Nach dem Ausführen des oberen Skripts hat das Verzeichnis folgenden Inhalt:

Root und Server Zertifikat

Root und Server Zertifikat

Das Skript generiert verschiedene (Zwischen-)Dateien, wovon für uns nur 2 wichtig sind:

  1. root.pfx (friendly name ‘Noser Engineering self-signed root cert’)
  2. server.pfx (friendly name ‘Noser Engineering self-signed server cert’)

Die Datei ‘root.pfx’ enthält das Zertifikat mit ‘Intended Purposes All’ und wird zum Signieren des Server- und Client-Zertifikates verwendet. Das Server-Zertifikat hat ‘Intended Purposes Server Authentication’ und wird später im gRPC Server geladen. Die Zertifikate müssen aber zuerst auf dem Rechner installiert werden.

Installieren der Zertifikate

Da es nicht möglich ist, mit OpenSSL den ‘friendly name’ in einer ‘crt’-Datei zu generieren, verwenden wir die ‘pfx’-Datei zum Installieren der Zertifikate.
Doppelklick auf root.pfx und ‘Local Machine’ wählen.

Importieren Zertifikat

Importieren Zertifikat

Das Passwort einfügen (P@ssw0rd).

Importieren Zertifikat

Importieren Zertifikat: Passwort spezifizieren

Für das Root-Zertifikate den ‘Trusted Root Certification Authorities’ Store auswählen.

Importieren Zertifikat: Store auswählen

Importieren Zertifikat: Trusted Root Store auswählen

Alle Schritte für ‘server.pfx’ wiederholen, mit dem Unterschied, dass ‘Intermediate Certification Authorities’ als Store gewählt werden soll.

Zertifikat Importieren: Intermediate Store auswählen

Zertifikat Importieren: Intermediate Store auswählen

Danach die Microsoft Management Konsole öffnen durch Eingabe von ‘cert’ im Windows Startmenü. Es erscheint ‘Manage computer certificates’ in den Ergebnissen, welches die Konsole öffnet.
Das Root-Zertifikat soll sich jetzt in ‘Trusted Root Certification Authorities’ befinden.

Root Zertifikat im Root Store

Root Zertifikat im Root Store

Und das Server-Zertifikat in ‘Intermediate Certification Authorities’.

Server-Zertifikat in Intermediate Certification Authorities store

Server-Zertifikat in Intermediate Certification Authorities store

gRPC Server Einrichten

In diesem Abschnitt wird der Kestrel-Server für eine HTTPS-Verbindung konfiguriert. Dazu wird das Server-Zertifikat gebraucht, welches gerade generiert und installiert wurde. Das Beispielprojekt ‘RpcOverHTTPSServer’ dient als Grundlage für die nächsten Blogs und kann hier als ZIP-Datei heruntergeladen werden.

Die Datei ‘server.pfx’ muss ins Serverprojekt kopiert und beim Builden ins Ausgabeverzeichnis kopiert werden.

Server.pfx file in server Projekt installieren

Server.pfx file in server Projekt installieren

Passwort und Dateiname werden in appsettings.json vom Serverprojekt in einer neuen Sektion ‘Certificate’ definiert:

{
  "Logging": {
  …
  },
  "Certificate": {
    "File": "server.pfx",
    "Password": "P@ssw0rd"
  }
}

In der program.cs Datei kann jetzt der Kestrel-Server für eine HTTPS-Verbindung konfiguriert werden:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
            webBuilder.ConfigureKestrel(
                opt =>
                {
                    var config = (IConfiguration)opt.ApplicationServices.GetService(typeof(IConfiguration));
                    var cert = new X509Certificate2(
                        config["Certificate:File"], config["Certificate:Password"]);
                    opt.ConfigureHttpsDefaults(
                        h =>
                        {
                            h.ClientCertificateMode = ClientCertificateMode.NoCertificate;
                            h.CheckCertificateRevocation = false;
                            h.ServerCertificate = cert;
                        });

                });
        });

Der KestrelServerOptions-Parameter von ConfigureKestrel() enthält eine Instanz des DI-Containers, welche gebraucht wird, um die Implementation von IConfiguration zu holen. Mit IConfiguration kann der Dateiname und das Passwort des Zertifikates aus appsettings.json gelesen werden und eine X509-Zertifikat Instanz erstellt werden.

Die HTTPS-Verbindung wird ohne Client-Zertifikat Authentifizierung erstellt (ClientCertificateMode.NoCertificate). Client-Zertifikat Authentifizierung wird im nächsten Blog erklärt und sorgt dafür, dass der Server den Client authentifiziert, bevor der Client auf die Schnittstellen zugreifen darf. Damit wird verhindert, dass unbekannte Clients auf den Server zugreifen.

Weil das Zertifikat selbstsigniert ist, kann es nicht durch eine Zertifizierungsinstanz widerrufen werden. Ausserdem fehlt beim Zertifikat die URL, um kontrollieren zu können (OCSP – Online Certificate Status Protocol), ob das Zertifikat widerrufen wurde. Deshalb wird CheckCertificateRevocation auf false gesetzt.

Für lokale Tests gibt es die Datei ‘Properties\launchSettings.json’ welche beschreibt wie der Server gestartet werden soll. Wenn der Server mit ‘dotnet run’ gestartet wird, wird die Konfiguration mit ‘commandName: Project’ genommen. Wichtig ist, dass die applicationUrl auf https://localhost:5001 gesetzt wird und der Standard http://localhost:5000 gelöscht wird.

{
…
    "RpcOverHTTPS": {
      "commandName": "Project",
      "launchBrowser": false,
      "launchUrl": "",
      "applicationUrl": "https://localhost:5001",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

Jetzt den Server via Visual Studio 2019 starten oder im Command-Prompt zum Root des Projektes navigieren und dort tippen ‘dotnet run’.

Server starten mit Visual Studio

Server starten mit Visual Studio

Im Ausgabefenster steht jetzt ‘Now listening on: https://localhost:5001’.

Serverausgabe

Serverausgabe

gRPC Client

Der Client ist eine einfache Sache: Man muss nur den Kanal für ‘https://localhost:5001’ erstellen. Im Beispiel ist diese URL ausgelagert in appsettings.json (‘Service:ServiceUrl’).

protected DemoService.DemoServiceClient Client
{
    get
    {
        if (_client == null)
        {
            var handler = new HttpClientHandler();
            var client = new HttpClient(handler);
            var opt = new GrpcChannelOptions
            {
                HttpClient = client,
                LoggerFactory = _loggerFactory
            };
            ChannelBase channel = GrpcChannel.ForAddress(_config["Service:ServiceUrl"], opt);
            _client = new DemoService.DemoServiceClient(channel);
        }
        return _client;
    }
}

Der Client verbindet sich wie vorher mit dem Server, nur jetzt über eine gesicherte Verbindung.

Client-Ausgabe

Client-Ausgabe

Fazit

Standardmässig benutzt gRPC das HTTP/2 Protokoll über eine ungesicherte Verbindung. Dieses Beispiel zeigt, wie der Kestrel-Server für eine sichere Verbindung eingerichtet werden kann. Das Absichern selber funktioniert gleich wie für eine REST-Schnittstelle oder eine normale Internetseite. In einem der nächsten Blogs wird Authentifizierung und Autorisierung mit JWT Tokens erklärt. Wer das Token besitzt kann mit dem Token auf den Server zugreifen. Deshalb ist für JWT Token Authentifizierung eine gesicherte Verbindung eine absolute Voraussetzung.

← Voriger Post
Nächster Post →
Kommentare

3 Antworten zu “gRPC Tutorial Teil 4: HTTP/2 über HTTPS”

  1. […] Weil das JWT nicht verschlüsselt ist muss zwingend die Kommunikation über eine gesicherte Verbindung geschehen. Die Projekte im Beispiel benutzten den Kestrel-Server mit gesicherter Verbindung wie beschrieben in ‘gRPC Tutorial Teil 4: HTTP/2 über HTTPS’. […]

  2. […] Das Projekt benutzt den Kestrel-Server mit gesicherter Verbindung wie beschrieben in ‘gRPC Tutorial Teil 4: HTTP/2 über HTTPS’. […]

Schreiben Sie einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Newsletter - aktuelle Angebote, exklusive Tipps und spannende Neuigkeiten

 Jetzt anmelden
NACH OBEN
Zur Webcast Übersicht