Guide: Symmetrisk Kryptering i Python med Fernet
Når man bygger moderne applikationer, er beskyttelse af følsomme data afgørende. Uanset om det gælder adgangskoder, API-nøgler eller personlige brugeroplysninger, har du brug for pålidelig kryptering.
I Python-økosystemet er standardvalget til kryptografiske operationer biblioteket cryptography. Inden i dette bibliotek findes et modul kaldet Fernet, som tilbyder en utrolig simpel – men alligevel topsikker – måde at implementere symmetrisk kryptering på.
Denne artikel tager dig gennem, hvad Fernet er, hvordan det virker, og hvordan du bruger det i praksis.
Hvad er Fernet?
Fernet er en implementering af symmetrisk (også kaldet “secret key”) kryptering. At krypteringen er symmetrisk betyder ganske enkelt, at du bruger den samme nøgle til både at kryptere og dekryptere data.
Designfilosofien bag Fernet er at gøre kryptering så let for udviklere som overhovedet muligt, uden at gå på kompromis med sikkerheden. Det beskytter dig mod en række almindelige faldgruber ved automatisk at træffe de “rigtige” kryptografiske valg (som valg af algoritmer og konfiguration).
Når data (kaldet en besked) krypteres med Fernet garanteres det, at:
- Fortrolighed: En fil/besked kan ikke læses eller snages i uden den korrekte nøgle.
- Integritet og Autentificering (AEAD): Det kan teknisk bevises, at beskeden ikke er blevet manipuleret med undervejs. Hvis en angriber ændrer blot ét tegn i den krypterede tekst, vil Fernet afvise at dekryptere den og kaste en fejl.
- Tidsstempling: Hver besked rummer tiden for krypteringen, hvilket kan bruges til at afvise beskeder, der er “for gamle”.
Hvordan fungerer Fernet under motorhjelmen?
Selvom du ikke behøver kende til kryptografien, er det rart at vide, hvad biblioteket gør:
- Selve krypteringen: Udføres med standarden AES (Advanced Encryption Standard) i CBC-tilstand med 128-bit nøgler og PKCS7 padding. Det er den absolutte guldstandard for kryptering i dag.
- Autentificeringen: Udføres ved hjælp af HMAC (Hash-based Message Authentication Code) ved brug af SHA256. HMAC’en udregnes ud fra de krypterede data, så man kan tjekke, om de er ægte, før man prøver at dekryptere dem.
Sådan bruger du Fernet i Python
Før du starter, skal du installere cryptography biblioteket. Det gøres via terminalen:
pip install cryptography
1. Generering af en nøgle
Sikkerheden afhænger 100% af nøglen. Kompromitteres nøglen, er krypteringen værdiløs. Nøglen skal genereres sikkert (med tilfældighed) og holdes hemmelig (f.eks. i en .env fil, aldrig uploadet til GitHub!).
from cryptography.fernet import Fernet
# Generer en URL-safe base64-kodet 32-byte nøgle.
# Kør KUN dette én gang for at skabe din master key, som du gemmer sikkert.
key = Fernet.generate_key()
print(f"Min hemmelige nøgle: {key.decode()}")
# Outputtet vil ligne: b'g25V3a_E2vQJjTqYf5gT5j_s9N4r...'
2. Kryptering af data
Når du har din nøgle, kan du oprette et Fernet-objekt og begynde at kryptere. Husk, at Fernet kræver data i form af bytes, ikke strings, så tekst skal først encodes.
from cryptography.fernet import Fernet
# Din gemte nøgle (i virkeligheden ville du hente denne fra f.eks. miljøvariabler)
my_secret_key = b'_5sM7Qn_Rj_1bF_L3zP4Qo_Y7hB8V_X2...'
f = Fernet(my_secret_key)
# Beskeden, der skal beskyttes (som bytes)
message = b"Dette er en meget hemmelig besked om verdensherredommet!"
# Krypter beskeden
encrypted_message = f.encrypt(message)
print(f"Krypteret (Ciphertext): {encrypted_message}")
# Output: b'gAAAAABlX... (en lang streng af gibberish)'
En interessant egenskab ved Fernet er, at hvis du kører koden heroppe to gange med den samme nøgle og samme besked, vil den krypterede tekst (Ciphertext) være forskellig hver gang. Dette sker på grund af en unik “Initialization Vector” (IV), der tilføjes hver gang. Det gør krypteringen meget stærkere mod kryptoanalyse.
3. Dekryptering af data
Når modtageren (eller dit system på et senere tidspunkt) skal læse beskeden igen, anvender vi det samme Fernet-objekt med den samme nøgle til at sløret beskeden.
from cryptography.fernet import Fernet, InvalidToken
my_secret_key = b'_5sM7Qn_Rj_1bF_L3zP4Qo_Y7hB8V_X2...'
f = Fernet(my_secret_key)
# Din gemte, krypterede besked
encrypted_message = b'gAAAAABlX...'
try:
# Dekrypter tilbage til de originale bytes
decrypted_message = f.decrypt(encrypted_message)
# Gør bytes til en normal string igen for at kunne læse den
print(f"Dekrypteret: {decrypted_message.decode()}")
except InvalidToken:
# Denne exception kastes, hvis nøglen er forkert,
# eller hvis den krypterede tekst er blevet ændret / er korrupt.
print("Fejl: Kunne ikke dekryptere. Nøglen er forkert, eller data er manipuleret!")
4. Tidsbegrænsede beskeder (Token Expiration)
Nogle gange vil du have, at et stykke krypteret data – f.eks. et link til at nulstille et password – kun er validt i et stykke tid. Fordi Fernet bager tidsstemplet direkte ind i koden, kan du uden ekstra kodeværk få Fernet til at afvise gamle tokens.
Det gør du i dekrypteringsfasen via parameteren ttl (Time To Live i sekunder):
import time
from cryptography.fernet import Fernet
f = Fernet(Fernet.generate_key())
token = f.encrypt(b"Sikkerheds-token for bruger X")
# Vent f.eks. 11 sekunder
time.sleep(11)
try:
# Kræv at tokenet max er 10 sekunder gammelt
f.decrypt(token, ttl=10)
except Exception as e:
print("Token er udløbet!")
Praktisk håndtering af dine nøgler
Når du udvikler med Fernet, er selve krypteringen nem – det svære (og der det oftest går galt for udviklere) er nøglehåndteringen (Key Management). Her er de vigtigste do’s and don’ts:
- Sæt aldrig nøgler fast i din kildekode (Hardcoding)
Gem nøgler som miljøvariabler. Brug f.eks. biblioteket
python-dotenvtil at trække nøglen ind i din Python app. - Roter dine nøgler (Key Rotation)
Hvis du frygter, at en nøgle har været kompromitteret (eller som en rutine f.eks. årligt), tilbyder biblioteket
MultiFernet. Med det kan du opsætte en liste af nøgler, hvor data krypteres med den seneste nøgle, men du stadig kan dekryptere gammel data med de gamle nøgler, som er med i listen. - Del ikke koden Da Fernet er symmetrisk (altså single-key), må den IKKE bruges til public transmission eller til situationer, hvor du ikke har fuld kontrol over begge systemer. Hvis to forskellige parter skal kommunikere sikkert med hinanden asynkront, anvendes rykkes der oftest over til Asymmetrisk Kryptering (som RSA eller Elliptic Curve), hvor der benyttes et nøglepar (Public / Private Key).
Konklusion
Fernet-modulet i Pythons cryptography-bibliotek fungerer som en uundværlig kniv i sikkerhedskassen for enhver Python-udvikler. Ved at skjule de komplekse kryptografiske valg (som cipher-tilstande og tilfældige salt/vektor-genereringer) reducerer det gevaldigt chancen for at begå fatale sikkerhedsfejl under implementering af symmetrisk kryptering.
Vil du beskytte data hurtigt og sikkert mod nysgerrige blikke? Så er Fernet the way to go.
Kilder
- cryptography.io - Fernet - Officiel dokumentation for Fernet-implementeringen i Python.
- Fernet Spec - Den tekniske specifikation for Fernet-formatet.
- OWASP - Cryptographic Storage Cheat Sheet - Best practices for sikker opbevaring og kryptering af data.
- NIST SP 800-38A - NIST-standard for blok-cipher tilstande, herunder CBC.
> Quiz: Test din viden
1. Hvilken krypteringsalgoritme bruger Fernet internt?
2. Hvad bruger Fernet til autentificering af krypterede beskeder?
3. Hvad er Fernet guldstandarden for i Python?
4. Hvad er nøglelængden i Fernet?