0%

Eine Verbindung, viele Anfragen

HTTPS ist HTTP innerhalb von TLS

Jedes Byte in diesem Kurs war auf der Leitung lesbar. In Kapitel 7 hat dein Client ein Passwort in einem authorization-Header als gesendet, und das kann jeder umkehren, der es sieht. Dein Server hat Session-IDs in verteilt, und Schreibzugriffe trugen Bearer-Tokens. Das war nur sicher, weil jedes dieser Bytes innerhalb eines einzigen Rechners blieb, auf der . Über ein echtes Netzwerk gesendet, könnte jedes davon von jedem auf dem Weg gelesen und kopiert werden: im WLAN, beim Internetanbieter, von einem Proxy dazwischen. HTTPS ist der Weg, wie das Web das vermeidet, und es ändert weniger, als du vielleicht erwartest.

Dieselben Bytes, verpackt

HTTPS ist , gesendet durch , die Verschlüsselungsschicht, die du in Networks with Python kennengelernt hast. TLS sitzt zwischen der und den HTTP-Bytes:

http://books.example/books          https://books.example/books

HTTP bytes                          the same HTTP bytes
                                    TLS: encrypts and checks them
TCP connection to port 80           TCP connection to port 443

Eine https- bedeutet drei Dinge: Verbinde dich mit 443, außer die URL nennt einen anderen, führe vor allem anderen einen TLS-Handshake durch und sende dann genau das HTTP, das du den ganzen Kurs über geschrieben hast, durch die verschlüsselte Schicht. Die Anfragezeile, die Header, content-length, Chunks, die offene Verbindung und Connection: close bleiben alle unverändert. TLS weiß nicht, dass die Bytes HTTP sind, und es ist ihm egal.

Was TLS hinzufügt

TLS gibt einer Verbindung drei Dinge:

  • Verschlüsselung. Alles darin, Pfad und Query, jeder Header einschließlich cookie und authorization und jeder Body, reist als Bytes, die nur die beiden Enden lesen können.

  • Integrität. Wenn irgendetwas auf dem Weg ein Byte verändert, bemerkt das empfangende Ende es, und die Verbindung schlägt fehl, statt veränderte Daten weiterzugeben.

  • Identität des Servers. Der Server legt ein Zertifikat für seinen Namen vor, signiert von einer Stelle, der der Client vertraut, und der Client prüft, dass der Name zum Host in der URL passt. Ohne diese Prüfung könnte ein Client eine perfekt verschlüsselte Verbindung zu einem Betrüger aufbauen.

Manches bleibt sichtbar. Ein Beobachter sieht weiterhin die Adressen und Ports, wann die Verbindung geöffnet und geschlossen wird und ungefähr, wie viele Bytes in jede Richtung fließen. Meist sieht er auch den Namen des Servers, weil der Client ihn früh im Handshake nennt, damit der Server das richtige Zertifikat auswählen kann.

Jemand beobachtet eine HTTPS-Anfrage für /me, die ein Session-Cookie enthält. Was kann er lesen?

Basic-Zugangsdaten werden über HTTPS gesendet. Was ändert sich?

In Python

Das ssl der Standardbibliothek verpackt einen verbundenen . Diese Zeilen sind zum Lesen da, nicht zum Ausführen hier:

import socket
import ssl

host = "books.example"
context = ssl.create_default_context()
with socket.create_connection((host, 443), timeout=5) as sock:
    with context.wrap_socket(sock, server_hostname=host) as tls:
        tls.sendall(b"GET /books HTTP/1.1\r\nHost: books.example\r\nConnection: close\r\n\r\n")
        print(tls.recv(4096))

ssl.create_default_context() prüft standardmäßig das Zertifikat und den Hostnamen. http.client.HTTPSConnection(host, timeout=5), das https-Geschwister der Klasse, die du seit Kapitel 3 benutzt, übernimmt dieses Verpacken für dich. server_hostname ist der Name, der geprüft wird, und der Name, den der Client im Handshake nennt. Das , das wrap_socket zurückgibt, hat sendall und recv, also würden read_head, read_chunked und read_body genau so davon lesen wie von einem gewöhnlichen Socket.

Bei requests genügt eine https-URL: requests.get("https://books.example/books", timeout=5) führt den Handshake durch und prüft das Zertifikat, weil seine Einstellung verify standardmäßig eingeschaltet ist. Kapitel 10 kommt darauf zurück. Wer verify ausschaltet, behält die Verschlüsselung, wirft aber die Identität des Servers weg.

Warum nicht hier

Diese Website hat keinen TLS-Endpunkt. Der Übungsdienst und dein eigener Server sprechen gewöhnliches HTTP, und die Sandboxes der Lektionen erreichen nichts anderes. Keine Lektion hier kann also einen Handshake oder ein Zertifikat zeigen.

Wenn du Python auf deinem eigenen Computer und eine Internetverbindung hast, kannst du dir ein echtes ansehen. Dieser optionale Schritt gehört nicht zum Kurs, und nichts prüft ihn. Er gibt die TLS-Version und den Inhaber (subject) des Zertifikats einer Website deiner Wahl aus. Der Block ist für eine -Shell wie bash oder zsh gedacht. Unter Windows speicherst du die Python-Zeilen zwischen den EOF-Markierungen in einer Datei und führst sie mit python aus.

python3 - <<'EOF'
import socket
import ssl

host = "www.python.org"  # or any https site you choose
context = ssl.create_default_context()
with socket.create_connection((host, 443), timeout=5) as sock:
    with context.wrap_socket(sock, server_hostname=host) as tls:
        print(tls.version())
        print(tls.getpeercert()["subject"])
EOF

HTTP/2 und HTTP/3

Viele Websites antworten auf https mit HTTP/2. Es behält , und Header und ihre Bedeutung bei. Was es ändert, ist die Art, wie Nachrichten auf der Verbindung reisen. Statt Textzeilen sendet es binäre Frames, und es verschränkt viele Anfragen und Antworten gleichzeitig auf einer Verbindung, sodass keine Anfrage auf die vorherige wartet, wie deine es in fetch_many getan haben. Es komprimiert Header, und es schreibt jeden Header-Namen klein, so wie es deine Antwort- schon die ganze Zeit tun. HTTP/3 transportiert dieselben Nachrichten über QUIC, das auf statt auf TCP läuft und TLS eingebaut hat.

Was ändert HTTP/2?

Eine Client-Bibliothek wählt die Version für dich, und alles, was dieser Kurs gelehrt hat, von Methoden und Statuscodes bis zu Caching, Cookies und Authentifizierung, bedeutet in allen dreien dasselbe. Kapitel 10 greift requests und httpx auf, jetzt, wo du weißt, was jede davon für dich tut.