Zustand und Identität
Bytes als Text mit Base64
Jeder kann sich bei deinem Server anmelden, und der Client trägt die Session, die dabei herauskommt. Bevor die Anmeldung ein Passwort prüfen kann, brauchen Benutzername und Passwort einen Weg, in einer Anfrage zu reisen. Ein Header ist der naheliegende Ort, und er ist ein enger. In Kapitel 2 hast du gesehen, dass ein Headerwert auf einer Zeile steht, also nie \r oder \n enthalten kann, und in Kapitel 6, dass http.server einen ü enthalten, die in
Die Lösung ist, die Bytes in Text aus einer kleinen, sicheren Zeichenmenge zu verwandeln und diesen Text am anderen Ende wieder in dieselben Bytes zurückzuverwandeln. A bis Z, a bis z, 0 bis 9, + und /, dazu = zum Auffüllen.
Drei Bytes werden zu vier Zeichen
Base64 liest die Bytes jeweils zu dritt. Drei Bytes sind 24 Bits, die es in vier Gruppen zu je 6 Bits schneidet. Sechs Bits können von 0 bis 63 zählen, also wählt jede Gruppe eines der 64 Zeichen: 0 ist A, 25 ist Z, 26 ist a, 51 ist z, 52 ist 0, und 62 und 63 sind + und /. Hier sind die zwei Bytes von b"ab". Lies das Bild von oben: dieselben Bits, zuerst in Achter und dann in Sechser geschnitten.

a ist das Byte 01100001 und b ist 01100010. In Sechser geschnitten sind diese Bits 011000, 010110 und 0010. Es sind nur 16 Bits, also wird die dritte Gruppe mit zwei Null-Bits zu 001000 aufgefüllt. Die drei Gruppen sind die Zahlen 24, 22 und 8, also die Zeichen Y, W und I, und ein = steht für die Gruppe, die ganz fehlt. b"ab" wird zu YWI=. Eine letzte Gruppe aus einem Byte bekommt ==. Je drei Bytes, oder die ein oder zwei am Ende übrig gebliebenen, werden zu vier Zeichen, also ist der Text etwa ein Drittel länger als die Bytes.
Pythons base64 übernimmt das Zählen. base64.b64encode(data) nimmt Bytes und gibt den Base64-Text zurück, als Bytes aus diesen 64 Zeichen; base64.b64decode(text) nimmt diesen Text, als Bytes oder als str, und gibt die ursprünglichen Bytes zurück.
Was gibt das aus?
import base64
print(base64.b64encode(b"ab"), base64.b64decode("YWI="))
bytes(16) sind sechzehn Null-Bytes. Was gibt das aus?
import base64
print(len(base64.b64encode(bytes(16))), len(base64.b64encode(b"abc")))
Jetzt ein ganzer Hin- und Rückweg mit Text, der kein reines ASCII ist. Kodiere den
ë brauchte zwei Bytes, also ist zoë:x sechs Bytes lang, und sechs Bytes werden zu acht Zeichen ohne Auffüllen. Die zwei Bytes von ë sind jetzt einfache Buchstaben, also passt der Text in jeden Header. Die letzte Zeile gibt 16 8 aus: Zehn Bytes sind drei volle Gruppen und ein übriges Byte, und vier Bytes sind eine Gruppe und ein übriges Byte, wobei jeder Rest auf vier Zeichen aufgefüllt wird.
Strenges Dekodieren
b64decode ist standardmäßig nachsichtig. Zeichen außerhalb des Alphabets werden kommentarlos übersprungen:
Der erste Aufruf lässt das ! weg und gibt b'ana:b' zurück, als wäre nichts falsch. Mit validate=True löst jedes Zeichen außerhalb des Alphabets, auch ein Leerzeichen oder ein Zeilenumbruch, binascii.Error mit der Meldung Only base64 data is allowed aus. Fehlendes Auffüllen löst in beiden Fällen binascii.Error aus. binascii.Error ist eine Art von except ValueError es ab, zusammen mit dem UnicodeDecodeError, das .decode("utf-8") auslöst, wenn die Bytes kein UTF-8 sind.
Ein Server, der Zugangsdaten prüft, will die strenge Form. Ein Header mit verirrten Zeichen wurde nicht von einem Client geschrieben, der sich an die Regeln hält, und ihn stillschweigend zu reparieren heißt, etwas anzunehmen, das niemand senden wollte.
base64.b64decode("YW5h!OmI=") gibt b'ana:b' zurück. Was ändert validate=True?
Kodieren ist kein Verschlüsseln
Sieh dir an, was das Dekodieren gebraucht hat: den Text, und sonst nichts. Es gibt keinen Schlüssel und kein Geheimnis. Jeder, der Base64-Text sieht, kann ihn mit einem Aufruf umkehren, genau wie du gerade. Base64 ändert, wie Bytes aufgeschrieben werden; es verbirgt nichts.
Das ist für die nächste Lektion wichtig. Die Basic-Anmeldung von hashlib erzeugt, ist etwas anderes: Er macht aus Bytes einen kurzen Fingerabdruck, der sich nicht zurückverwandeln lässt.
Eine Anfrage trägt authorization: Basic YW5hOmNvcnJlY3QgaG9yc2U=. Wer kann das Passwort lesen?
Warum werden Benutzername und Passwort überhaupt kodiert?
Base64 taucht überall dort auf, wo Bytes als Text reisen müssen. Ein späterer Kurs in dieser Reihe, WebSockets with Python, ist geplant und wird es wieder verwenden, im Handshake, der eine HTTP-Verbindung in einen WebSocket verwandelt. Als Nächstes verwendet dein Server es, um Benutzername und Passwort aus einer Anmeldeanfrage zu lesen.