Hallo,
Da meine Antwort ein bißchen umfangreicher ausfällt habe ich sie in Abschnitte unterteilt.
1. Hintergrund
Da mir meine Daten sehr wichtig sind habe ich mir vor längerer Zeit einen eigenen DNS-Server (dnsmasq) auf einer Linux-Kiste eingerichtet, um Google und Konsorten auszubremsen (d.h. keine Datenspuren bei ihnen zu hinterlassen).
Also im Prinzip das was heute unter dem Namen "
Pi-Hole" vielen bekannt sein dürfte.
So werden z.B.
"*.google-analytics.com",
"*.googletagmanager.com" und
"*.googlesyndication.com"
per DNS "hart geerdet".
Da aber manche Sachen (z.B. JS-Libs) von Google und Konsorten durchaus nützlich sind, werden etwa
https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js
https://cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.0.6/cookieconsent.min.css
https://cdn.jsdelivr.net/bootstrap/3.3.7/css/bootstrap.min.css
zuerst über den DNS auf "127.0.0.1" aufgelöst und dann über einen lokal laufenden ("127.0.0.1") und in Java geschrieben HTTPS-Server ausgeliefert.
Als Haupt-Vorteile sind zu nennen:
- ich hinterlasse keine Datenspuren (Stichwort Referrer) bei Google & Co.
- schnellere Auslieferung, da lokal
- in den Logs sehe ich welchen "unerwünschten Datenverkehr" manche Seite erzeugen
- für einige JS-Dateien lassen sich auch "verbesserte" ;-) Versionen ausliefern!
Mein Java-HTTPS-Server basiert im Kern auf
https://stackoverflow.com/questions/2308479/simple-java-https-server --> SimpleHTTPSServer
ist aber in Sachen Funktionalität stark aufgebohrt.
Damit der Datenverkehr ordnungsgemäß verschlüsselt über http
s ablaufen kann sind natürlich auf dem Server und Client (z.B. Browser) Zertifikate notwendig.
Wie diese erzeugt werden und wo man sie wie hinpackt beschreibt der folgende Anschnitt:
2. Server-Seite
2.1 Schlüssel und Zertifikate
Die nachfolge Anleitung basiert hauptsächlich auf
https://jamielinux.com/docs/openssl-certificate-authority/introduction.html
, ich habe sie zur leichteren Nachvollziehbarkeit vereinfacht. Daher taugt diese
NICHT für den
professionellen Gebrauch!!!
Sie ist zu Übungszwecken und für den "Hausgebrauch" geeignet.
So wird z.B. immer wenn ein Passwort gefordert ist einfach "password" genutzt.
Für die Server-Seite werden 3 Schlüssel und 3 Zertifikate (jeweils in der Ausprägung Root-, Intermediate- und Server-) erzeugt.
Benötigte Werkzeuge/Programme sind:
Eine Übersicht für wichtige openssl-Befehle ist auf
https://wiki.openssl.org/index.php/Command_Line_Utilities
zu finden.
2.1.1 Root-Key / Root-Zertifikat
Zuerst wird der 4096-Bit Root-Key erzeugt. Dies geschieht per
openssl genrsa -aes256 -out root.key.pem 4096
Bei der Frage nach dem Passwort geben wir (zweimal) "password" an.
Um sich das Ergebnis auszusehen tippt man
openssl rsa -in root.key.pem -text
ein.
Zur Erzeugung des Root-Zertikates benötigen wir eine Konfigurationsdatei, dazu den folgenden Text als "openssl_root.cnf" abspeichern:
Code:
# based on https://jamielinux.com/docs/openssl-certificate-authority/appendix/root-configuration-file.html
# OpenSSL root CA configuration file.
[ ca ]
# `man ca`
default_ca = CA_default
[ CA_default ]
# Directory and file locations.
new_certs_dir = .
database = index.txt
serial = serial.txt
# The root key and root certificate.
private_key = root.key.pem
certificate = root.cert.pem
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 375
preserve = no
policy = policy_strict
[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
# See the POLICY FORMAT section of `man ca`.
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
# Options for the `req` tool (`man req`).
default_bits = 2048
distinguished_name = req_distinguished_name
string_mask = utf8only
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
# Extension to add when the -x509 option is used.
x509_extensions = v3_ca
[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address
# Optionally, specify some defaults.
countryName_default = FR
stateOrProvinceName_default = Paris
localityName_default = Paris
0.organizationName_default = DS Global Digital Certificates
organizationalUnitName_default =
commonName_default = DS Global Digital Certificates Root Cert
emailAddress_default =
[ v3_ca ]
# Extensions for a typical CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ usr_cert ]
# Extensions for client certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
[ server_cert ]
# Extensions for server certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[ crl_ext ]
# Extension for CRLs (`man x509v3_config`).
authorityKeyIdentifier=keyid:always
[ ocsp ]
# Extension for OCSP signing certificates (`man ocsp`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning
Wie man sieht wird das Zertifikat von der
fiktiven Firma "DS Global Digital Certificates" in Paris, Frankreich ausgestellt.
Eine kleine Hommage an die Citroen DS!
Diese Daten können natürlich nach eigenem Gusto verändert werden.
Das Root-Zertifikat wird mit
openssl req -config openssl_root.cnf -key root.key.pem -new -x509 -days 5844 -sha256 -extensions v3_ca -out root.cert.pem
erzeugt und läuft 16 Jahre(=5844 Tage).
Bei der Frage nach der "pass phrase" einfach wieder "password" angeben, bei den anderen Fragen einfach "Return" drücken.
Um sich das Root-Zertifikat anzusehen gibt es den Befehl
openssl x509 -noout -text -in root.cert.pem
2.1.2 Intermediate-Key / Intermediate-Zertifikat
Bei professionellen Zertifikaten wird in aller Regel ein Intermediate (= Zwischen)-Zertifikat ausgestellt.
Auf die Gründe gehe ich hier
nicht ein!
Die Erzeugung des Intermediate-Keys erfolgt analog zu oben per
openssl genrsa -aes256 -out intermediate1.key.pem 4096
Bei der Frage nach dem Passwort geben wir wieder (zweimal) "password" an.
Ansehen kann man sich das Ganze wieder mit
openssl rsa -in intermediate1.key.pem -text
Für den nächsten Schritt benötigen wir wieder ein Konfigurations-Datei, die wie folgt aussieht:
Code:
# based on https://jamielinux.com/docs/openssl-certificate-authority/appendix/intermediate-configuration-file.html
# OpenSSL intermediate CA configuration file.
[ ca ]
# `man ca`
default_ca = CA_default
[ CA_default ]
# Directory and file locations.
new_certs_dir = .
database = intermediate_index.txt
serial = intermediate_serial.txt
########################################################### ALF
copy_extensions = copy
# The root key and root certificate.
private_key = intermediate1.key.pem
certificate = intermediate1.cert.pem
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 375
preserve = no
policy = policy_loose
[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
# See the POLICY FORMAT section of `man ca`.
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
# Options for the `req` tool (`man req`).
default_bits = 2048
distinguished_name = req_distinguished_name
string_mask = utf8only
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
# Extension to add when the -x509 option is used.
x509_extensions = v3_ca
[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address
# Optionally, specify some defaults.
countryName_default = FR
stateOrProvinceName_default = Paris
localityName_default = Paris
0.organizationName_default = DS Global Digital Certificates
organizationalUnitName_default =
commonName_default = DS Global Digital Certificates Intermediate X1 2019
emailAddress_default =
[ v3_ca ]
# Extensions for a typical CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ usr_cert ]
# Extensions for client certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
[ server_cert ]
# Extensions for server certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[ crl_ext ]
# Extension for CRLs (`man x509v3_config`).
authorityKeyIdentifier=keyid:always
[ ocsp ]
# Extension for OCSP signing certificates (`man ocsp`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning
Obige Zeilen als "openssl_intermediate1.cnf" abspeichern.
Dann einen sog. "certificate signing request" (csr) mittels
openssl req -config openssl_intermediate1.cnf -new -sha256 -key intermediate1.key.pem -out intermediate1.csr.pem
generieren. Die Frage(n) nach dem Passwort wie üblich mit "password" benantworten, die übrigen einfach mit "Return" bestätigen.
Als Voraussetzung für den nächsten Schritt benötigen wir noch die Datei "index.txt", die per
touch index.txt
erzeugt wird und die Datei "serial.txt", welche ihrerseits mit
echo 1000 >serial.txt
mit dem richtigen Inhalt befüllt wird.
Jetzt wird das Intermediate-Zertifikat mit
openssl ca -config openssl_root.cnf -extensions v3_intermediate_ca -days 3650 -notext -md sha256 -in intermediate1.csr.pem -out intermediate1.cert.pem
signiert. Frage nach dem Passwort wie üblich mit "password", die Frage, ob das Zertifikat signiert werden soll mit "y" beantworten.
Jetzt haben wir ein signiertes Zwischen-Zertifikat ("intermediate1.cert.pem"), dessen Inhalt wir mit
openssl x509 -noout -text -in intermediate1.cert.pem
begutachten können.
Ob die Signierung auch erfolgreich geklappt hat kann man mit
openssl verify -CAfile root.cert.pem intermediate1.cert.pem
überprüfen.
2.1.3 Server-Key / Server-Zertifikat
Der Server-Key wird
openssl genrsa -out server1.key.pem 2048
erzeugt. Hierbei fällt gegenüber oben auf, daß hier "nur" mit 2048 Bits gearbeitet wird und daß
nicht nach einem Passwort gefragt wird, dies liegt daran, daß der Parameter "-aes256" fehlt. Wer diese "Sicherheitslücke" nicht haben will kann auch
mit Passwort arbeiten.
Um den "certificate signing request" (CSR) für das Server-Zertifikat zu erzeugen, benötigen wir wieder eine Konfigurations-Datei "openssl_server1.cnf", die wie folgt aussieht
Code:
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
x509_extensions = v3_ca
#prompt = no
[req_distinguished_name]
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address
# Optionally, specify some defaults.
countryName_default = DE
stateOrProvinceName_default = Bayern
localityName_default = Munich
0.organizationName_default = HTTPS Secure Web Services GmbH
organizationalUnitName_default =
commonName_default = Server S1
emailAddress_default =
[v3_req]
subjectAltName = @alt_names
keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
[v3_ca]
subjectAltName = @alt_names
[alt_names]
DNS.1=*.googleapis.com
DNS.2=*.googlesyndication.com
DNS.3=*.googleadservices.com
DNS.4=*.googletagmanager.com
DNS.5=*.googletagservices.com
DNS.6=*.google-analytics.com
DNS.7=apis.google.com
DNS.8=*.cloudflare.com
DNS.9=*.jsdelivr.net
DNS.10=*.citroends4.de
DNS.11=*.citroends4.com
IP.1=127.0.0.1
IP.2=192.168.12.34
Man sieht, daß das Server-Zertifikat auf die
fiktive Firma "HTTPS Secure Web Services GmbH", die sich in München/Bayern/Deutschland befindet, ausgestellt ist.
Der Name des Zertifikates ist "Server S1".
Diese Angaben kann man wieder nach den persönlichen Bedürfnissen anpassen.
Der
wichtige(re) Teil befindet sich allerdings ganz unten nach der Zeile "[alt_names]", hier kann/soll/muss man die Namen (DNS.<Nummer>) bzw. die IP-Adressen (IP.<Nummer>), auf die der HTTPS-Server "hören" soll eintragen.
Um nun den CSR zu erhalten gibt man den Befehl
openssl req -config openssl_server1.cnf -key server1.key.pem -new -sha256 -out server1.csr.pem
ein. Nach dem Passwort wird dieses mal
nicht gefragt, da wir ja oben keines vergeben haben, alle sonstigen Fragen einfach wieder per "Return" bestätigen.
Um sich den CSR anzusehen wird der Befehl
openssl req -in server15.csr.pem -noout -text
verwendet.
Zur Vorbereitung des nächsten Schrittes benötigen wir die Dateien "intermediate_index.txt" und "intermediate_serial.txt", die mit
touch intermediate_index.txt
und
echo 2001 >intermediate_serial.txt
erzeugt werden.
Mithilfe dieser beiden Dateien kann die Signierung durchgeführt werden:
openssl ca -config openssl_intermediate1.cnf -extensions server_cert -days 1828 -notext -md sha256 -in server1.csr.pem -out server1.cert.pem
Passwort ist wieder "password", alle anderen Fragen mit "y" (für Ja) beantworten.
Durch den letzten Schritt sind wir nun stolzer Besitzer eines signierten Server-Zertifikates ("server1.cert.pem")!!!
Dieses können wir mit
openssl x509 -noout -text -in server1.cert.pem
in all seiner Schönheit bewundern!
2.1.4 Erzeugung JKS-Dateien für Java
Seltsamerweise (zumindest ich kann es mir nicht erklären) möchte Java unter Windows bzw. unter Linux die JKS-Datei in unterschiedlichen Formaten haben.
Für Windows ist dies im sog. "pkcs12"-Format der Fall, für Linux ist das "JKS"-Format gewünscht.
Um die Datei(-en) "server1.jks" (für Windows) bzw. "server1_JKS.jks" (für Linux) zu erzeugen muss man als Vorarbeit zunächst alle oben generierten Zertifikate plus den Server-Key
in
eine Datei "all1.pem" packen, dies geschieht per
cat root.cert.pem intermediate1.cert.pem server1.cert.pem server1.key.pem >all1.pem
Danach erzeugen wir die Datei "server1.p12" mit
openssl pkcs12 -export -inkey server1.key.pem -in all1.pem -name server1 -out server1.p12
die wir als Eingangsdatei für das Java-Programm "keytool" benötigen. Wie üblich Passwort "password".
Unter
Windows importieren wir unsere "server1.p12"-Datei mit
keytool -importkeystore -srckeystore server1.p12 -srcstoretype pkcs12 -deststoretype pkcs12 -storepass password -destkeystore server1.jks
unter
Linux geschieht derselbe Schritt per
keytool -importkeystore -srckeystore server1.p12 -srcstoretype pkcs12 -deststoretype JKS -storepass password -destkeystore server1_JKS.jks
Das Passwort ist "password", als Ausgabe sollte etwas mit "... erfolgreich importiert" erscheinen.
Um sich das Ergebnis des obigen Importes anzusehen bedarf es des Befehls
keytool -list -v -keystore server1.jks
Hier sollten die 3 Zertifikate (Root-, Intermediate- und Server-Zertifikat) plus der private Server-Key angezeigt werden.
2.1.5 Java Https-Server starten
Wie weiter oben schon erwähnt basiert mein Java HTTPS-Server auf
https://stackoverflow.com/questions/2308479/simple-java-https-server --> SimpleHTTPSServer
Wir verwenden hier eine minimal abgewandelte Version, die auf Port 443 läuft und den Context "/" hat (siehe: httpsServer.createContext("/", new MyHandler()); ).
Der Name für die JKS-Datei "server1.jks"(
Windows) bzw. server1_JKS.jks"(
Linux) wurde ebenfalls an unsere Gegebenheiten angepasst.
Das Passwort (siehe: char[] password = "password".toCharArray(); ) stimmt
zufällig mit unserem überein.
Außerdem habe ich in die "MyHandler"-Methode noch ein paar Ausgaben eingebaut.
Folgendes als "SimpleHTTPSServer.java" abspeichern
Code:
import java.io.*;
import java.net.InetSocketAddress;
import java.lang.*;
import java.net.URL;
import com.sun.net.httpserver.HttpsServer;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import com.sun.net.httpserver.*;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URLConnection;
import java.net.URI;
import java.util.Date;
import java.util.Map;
import java.util.List;
import java.text.SimpleDateFormat;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
import java.net.InetAddress;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsExchange;
public class SimpleHTTPSServer {
public static class MyHandler implements HttpHandler {
@Override
public void handle(HttpExchange t) throws IOException {
HttpsExchange httpsExchange = (HttpsExchange) t;
URI uri = t.getRequestURI();
String query = uri.getQuery();
Map<String, List<String>> headers= t.getRequestHeaders();
String host= "";
if (headers.get("Host")!=null) host= headers.get("Host").get(0);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(new Date()) + " " + t.getRequestMethod() + " " + t.getProtocol() + " https://" + host + uri.getPath() + (query==null ? "" : "?" + query) );
for(String s: headers.keySet() )
{
System.out.printf(" %-18s ", s);
int values= 0;
for(String v: headers.get(s) )
{
if (values>0) System.out.print(" | ");
System.out.print(v);
values++;
}
System.out.println(" ");
}
String response = "This is the response";
t.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
t.sendResponseHeaders(200, response.getBytes().length);
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
/**
* @param args
*/
public static void main(String[] args) throws Exception {
try {
// setup the socket address
InetSocketAddress address = new InetSocketAddress(443);
// initialise the HTTPS server
HttpsServer httpsServer = HttpsServer.create(address, 0);
SSLContext sslContext = SSLContext.getInstance("TLS");
// initialise the keystore
char[] password = "password".toCharArray();
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream("server1.jks");
ks.load(fis, password);
// setup the key manager factory
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, password);
// setup the trust manager factory
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);
// setup the HTTPS context and parameters
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
public void configure(HttpsParameters params) {
try {
// initialise the SSL context
SSLContext context = getSSLContext();
SSLEngine engine = context.createSSLEngine();
params.setNeedClientAuth(false);
params.setCipherSuites(engine.getEnabledCipherSuites());
params.setProtocols(engine.getEnabledProtocols());
// Set the SSL parameters
SSLParameters sslParameters = context.getSupportedSSLParameters();
params.setSSLParameters(sslParameters);
} catch (Exception ex) {
System.out.println("Failed to create HTTPS port");
}
}
});
httpsServer.createContext("/", new MyHandler());
httpsServer.setExecutor(null); // creates a default executor
httpsServer.start();
} catch (Exception exception) {
System.out.println("Failed to create HTTPS server on port " + 443 + " of localhost");
exception.printStackTrace();
}
}
}
und per
javac SimpleHTTPSServer.java
kompilieren.
Dann mit
java SimpleHTTPSServer
starten.
3. Client-Seite
Nachdem die Server-Seite abgeschlossen ist, wenden wir uns nun der Client-Seite zu.
Nachfolgend werden nur der Firefox-Browser und die auf Chromium basierenden Browser (Google Chrome, Edge, Opera, Vivaldi) betrachtet.
3.1 Chromium basierende Browser (Google Chrome, Edge, Opera, Vivaldi)
Da diese Browser den Windows-eigenen Zertifikat-Store verwenden, müssen wir nur unser Root-Zertifikat nach Windows importieren.
Eigentlich würde dafür die Datei "root.cert.pem" genügen, dies hat allerdings den kleinen optischen Nachteil, daß der Zertifikatsinhaber
nicht angezeigt wird.
Um diesen optischen Mangel zu beheben wandeln wir unser Root-Zertifikat mit
openssl pkcs12 -export -in root.cert.pem -cacerts -nokeys -caname "DS Global Digital Certificates Root Cert" -out root_with_nice_name.pfx
in die Datei "root_with_nice_name.pfx" um, die wir nun in den Windows Zertifikat-Store importieren.
Dies geschieht am einfachsten mit
(linke Windows-Taste) + "R" ---> certmgr.msc ---> OK
Es öffnet sich ein Fenster "certmgr", in diesem auf
Vertrauenswürdige Stammzertifizierungsstellen ---> Zertifikate
klicken.
Nun per
Rechtsklick auf
Vertrauenswürdige Stammzertifizierungsstellen ---> Zertifikate ---> Alle Aufgaben... ---> Importieren
den Import starten und als "Zu importierende Datei" unser oben erzeugtes "root_with_nice_name.pfx" (evtl. den Datei-Typ auf ".pfx" ändern).
Ansonsten alle Einstellungen lassen, das Passwort ist "password". Nach
Weiter ---> Weiter ---> Weiter ---> Fertigstellen
ist das Root-Zertifikat im Windows-Zertifikat-Store einsatzbereit.
Unter
"DS Global Digital Certificates Root Cert" ---> Doppelklick
kann man sich das erfolgreich importierte Werk nochmal ansehen.
Daß letztendlich auch alles funktioniert kann man sogleich im Browser durch die Eingabe von
https://127.0.0.1/
überprüfen, welche dieser mit einem freundlichen "This is the response" beantworten sollte.
Per Klick auf das
Schloss-Symbol ---> Zertifikat (Gültig) ---> Zertifizierungspfad
sehen wir die gesamte Zertifikats-Kette bestehend aus den 3 oben erzeugten Zertifikaten.
Sieht man sich die zugehörige Ausgabe des "SimpleHTTPSServer"s an, so erkennt man, daß nicht nur die URL "
https://127.0.0.1" angefordert wurde, sondern auch noch das zugehörige "favicon.ico":
(Hinweis: Die Uhrzeiten sind gefaked!)
Code:
2019-12-15 49:87:94 GET HTTP/1.1 https://127.0.0.1/
Accept-encoding gzip, deflate, br
Accept text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Sec-fetch-user ?1
Connection keep-alive
Host 127.0.0.1
Sec-fetch-site none
Sec-fetch-mode navigate
User-agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36
Accept-language de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
Upgrade-insecure-requests 1
2019-12-15 49:87:94 GET HTTP/1.1 https://127.0.0.1/favicon.ico
Accept-encoding gzip, deflate, br
Accept image/webp,image/apng,image/*,*/*;q=0.8
Connection keep-alive
Referer https://127.0.0.1/
Host 127.0.0.1
Sec-fetch-site same-origin
Sec-fetch-mode no-cors
User-agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36
Accept-language de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
Richtig interessant wird es beim Aufruf einer Seite, die eine Datei von "
https://ajax.googleapis.com/" einbindet:
Ich habe mir als Beispiel mal
https://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_lib_google
ausgewählt.
Die zugehörige Ausgabe von "SimpleHTTPSServer" ist (Uhrzeiten wieder gefaked!):
Code:
2019-12-15 55:88:95 GET HTTP/1.1 https://fonts.googleapis.com/css?family=Source Code Pro
Accept-encoding gzip, deflate, br
Accept text/css,*/*;q=0.1
Connection keep-alive
Referer https://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_lib_google
Host fonts.googleapis.com
Sec-fetch-site cross-site
Sec-fetch-mode no-cors
User-agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36
Accept-language de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
2019-12-15 55:88:95 GET HTTP/1.1 https://apis.google.com/js/client.js?onload=checkAuth
Accept-encoding gzip, deflate, br
Accept */*
Connection keep-alive
Referer https://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_lib_google
Host apis.google.com
Sec-fetch-site cross-site
Sec-fetch-mode no-cors
User-agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36
Accept-language de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
2019-12-15 55:88:95 GET HTTP/1.1 https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js
Accept-encoding gzip, deflate, br
Accept */*
Connection keep-alive
Referer https://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_lib_google
Host ajax.googleapis.com
Sec-fetch-site cross-site
Sec-fetch-mode no-cors
User-agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36
Accept-language de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
Im "Normalfall" gehen alle diese Angaben (
inklusive der IP-Adresse) und insbesondere der "Refer(r)er" (=
https://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_lib_google) an Google!!!
3.2 Firefox-Browser
Da der Firefox-Browser seinen eigenen Zertifikat-Store hat muss man hier anders vorgehen:
Im Browser eingeben
about:preferences#privacy ---> Zertifikate anzeigen... ---> Zertifizierungsstellen ---> Importieren...
dann die Datei "root.cert.pem" auswählen, danach ein Häckchen bei
Dieser CA vertrauen, um Websites zu identifizieren.
machen.
Nach einem finalem
OK
sollte das Root-Zertifikat importiert sein.
Dies kann man durch runterscrollen auf "DS Global Digital Certificates Root Cert" und durch Doppelklick auf ebendiesen Eintrag überprüfen.
Nach der Eingabe von
https://127.0.0.1/
in die Adresszeile sollte ein "This is the response" als Antwort erscheinen.
==================================================
Zusätzlicher Hinweis für "
CitroenDsVier":
Wenn Du diese Anleitung komplett abgearbeitet hast bist Du nun im Besitz der Datei "server1_JKS.jks".
Diese musst Du in Deinem Server laden.
Also wie in der von Dir geposteten Anleitung auf
http://sparkjava.com/documentation ---> How do I enable SSL/HTTPS?
in die Zeile
Code:
String keyStoreLocation = "server1_JKS.jks ";
die oben erzeugte Datei "server1_JKS.jks" (mit Pfad) eingeben.
Außerdem musst Du noch die IP-Adresse Deines Servers in die Datei "openssl_server1.cnf" (Abschnitt 2.1.3) eintragen.
HTH
BigNum