Toestand en identiteit
Bytes als tekst met Base64
Iedereen kan op je server inloggen, en de client draagt de sessie die daaruit volgt. Voordat de login een wachtwoord kan controleren, hebben de gebruikersnaam en het wachtwoord een manier nodig om in een verzoek te reizen. Een header is de voor de hand liggende plek, en een smalle. In hoofdstuk 2 zag je dat een headerwaarde op één regel staat, dus hij kan nooit \r of \n bevatten, en in hoofdstuk 6 dat http.server niet eens een ü die in
De oplossing is de bytes omzetten in tekst die uit een kleine, veilige set tekens bestaat, en die tekst aan de andere kant weer omzetten in dezelfde bytes. A tot en met Z, a tot en met z, 0 tot en met 9, + en /, plus = als opvulling.
Drie bytes worden vier tekens
Base64 leest de bytes per drie. Drie bytes zijn 24 bits, die het in vier groepen van 6 bits knipt. Met zes bits kun je van 0 tot 63 tellen, dus elke groep kiest een van de 64 tekens: 0 is A, 25 is Z, 26 is a, 51 is z, 52 is 0, en 62 en 63 zijn + en /. Hier zijn de twee bytes van b"ab". Lees de afbeelding van boven: dezelfde bits, eerst in achten geknipt en daarna in zessen.

a is de byte 01100001 en b is 01100010. In zessen geknipt zijn die bits 011000, 010110 en 0010. Er zijn maar 16 bits, dus de derde groep wordt met twee nulbits aangevuld tot 001000. De drie groepen zijn de getallen 24, 22 en 8, en dat zijn de tekens Y, W en I, en een = staat voor de groep die helemaal ontbreekt. b"ab" wordt YWI=. Een laatste groep van één byte krijgt ==. Elke drie bytes, of de een of twee die aan het eind overblijven, worden vier tekens, dus de tekst is ongeveer een derde langer dan de bytes.
De base64 van Python doet het tellen. base64.b64encode(data) neemt bytes en geeft de base64-tekst terug, als bytes die uit die 64 tekens bestaan; base64.b64decode(text) neemt die tekst, als bytes of als str, en geeft de oorspronkelijke bytes terug.
Wat drukt dit af?
import base64
print(base64.b64encode(b"ab"), base64.b64decode("YWI="))
bytes(16) is zestien nulbytes. Wat drukt dit af?
import base64
print(len(base64.b64encode(bytes(16))), len(base64.b64encode(b"abc")))
Nu een hele heen-en-terugreis met tekst die geen gewone ASCII is. Codeer de
ë nam twee bytes in, dus zoë:x is zes bytes, en zes bytes worden acht tekens zonder opvulling. De twee bytes van ë zijn nu gewone letters, dus de tekst past in elke header. De laatste regel drukt 16 8 af: tien bytes zijn drie volle groepen en één overgebleven byte, en vier bytes zijn één groep en één overgebleven byte, waarbij elke rest wordt aangevuld tot vier tekens.
Strikt decoderen
b64decode is standaard vergevingsgezind. Tekens buiten het alfabet worden zonder melding overgeslagen:
De eerste aanroep laat de ! vallen en geeft b'ana:b' terug, alsof er niets mis is. Met validate=True werpt elk teken buiten het alfabet, ook een spatie of een regeleinde, binascii.Error op met de melding Only base64 data is allowed. Ontbrekende opvulling werpt hoe dan ook binascii.Error op. binascii.Error is een soort except ValueError vangt hem op, samen met de UnicodeDecodeError die .decode("utf-8") opwerpt als de bytes geen UTF-8 zijn.
Een server die inloggegevens controleert, wil de strikte vorm. Een header met verdwaalde tekens is niet geschreven door een client die de regels volgt, en hem stilletjes repareren betekent iets accepteren wat niemand bedoelde te sturen.
base64.b64decode("YW5h!OmI=") geeft b'ana:b' terug. Wat verandert validate=True?
Coderen is geen versleutelen
Kijk wat het decoderen nodig had: de tekst, en verder niets. Er is geen sleutel en geen geheim. Iedereen die base64-tekst ziet, kan die met één aanroep terugdraaien, precies zoals jij net deed. Base64 verandert hoe bytes worden opgeschreven; het verbergt niets.
Dat doet ertoe voor de volgende les. De Basic-login van hashlib maakt, is anders: die maakt van bytes een korte vingerafdruk die niet kan worden teruggedraaid.
Een verzoek draagt authorization: Basic YW5hOmNvcnJlY3QgaG9yc2U=. Wie kan het wachtwoord lezen?
Waarom codeer je de gebruikersnaam en het wachtwoord überhaupt?
Base64 duikt op overal waar bytes als tekst moeten reizen. Een latere cursus in deze reeks, WebSockets with Python, is gepland en zal het opnieuw gebruiken, in de handshake die een HTTP-verbinding in een WebSocket verandert. Hierna gebruikt je server het om een gebruikersnaam en wachtwoord uit een loginverzoek te lezen.