Sikker hashing med Python Hashlib

Denne vejledning vil lære dig, hvordan du opretter sikre hashes ved hjælp af indbygget funktionalitet fra Pythons hashlib-modul.

Det kan være nyttigt at forstå betydningen af ​​hashing, og hvordan man programmæssigt beregner sikre hashes – også selvom du ikke arbejder med applikationssikkerhed. Men hvorfor?

Nå, når du arbejder på Python-projekter, vil du sandsynligvis støde på tilfælde, hvor du er bekymret for at gemme adgangskoder og andre følsomme oplysninger i databaser eller kildekodefiler. I sådanne tilfælde er det mere sikkert at køre hashing-algoritmen på følsomme oplysninger og gemme hashen i stedet for oplysningerne.

I denne guide vil vi dække, hvad hashing er, og hvordan det adskiller sig fra kryptering. Vi vil også gennemgå egenskaberne for sikre hash-funktioner. Derefter vil vi bruge almindelige hashing-algoritmer til at beregne hashen af ​​almindelig tekst i Python. For at gøre dette bruger vi det indbyggede hashlib-modul.

For alt dette og mere, lad os komme i gang!

Hvad er hashing?

Processen med hashing optager en meddelelsesstreng og giver et output med fast længde kaldet hash. Det betyder, at længden af ​​output-hashen for en given hashing-algoritme er fast – uanset længden af ​​input. Men hvordan adskiller det sig fra kryptering?

Ved kryptering er beskeden eller almindelig tekst krypteret ved hjælp af en krypteringsalgoritme, der giver et krypteret output. Vi kan derefter køre dekrypteringsalgoritmen på det krypterede output for at få beskedstrengen tilbage.

Dog fungerer hashing anderledes. Vi har lige lært, at krypteringsprocessen er inverterbar, idet du kan gå fra den krypterede besked til den ukrypterede besked og omvendt.

I modsætning til kryptering er hashing ikke en inverterbar proces, hvilket betyder, at vi ikke kan gå fra hashen til inputmeddelelsen.

Egenskaber for hash-funktioner

Lad os hurtigt gennemgå nogle egenskaber, som hash-funktioner skal opfylde:

  • Deterministisk: Hash-funktioner er deterministiske. Givet en besked m, er hashen af ​​m altid den samme.
  • Preimage Resistant: Vi har allerede dækket dette, da vi sagde, at hashing ikke er en inverterbar operation. Preimage modstandsegenskaben angiver, at det er umuligt at finde meddelelsen m fra output-hashen.
  • Kollisionsbestandig: Det burde være svært (eller beregningsmæssigt umuligt) at finde to forskellige meddelelsesstrenge m1 og m2, således at hashen af ​​m1 er lig med hashen af ​​m2. Denne egenskab kaldes kollisionsmodstand.
  • Andet Preimage Resistant: Dette betyder, at givet en besked m1 og den tilsvarende hash m2, er det umuligt at finde en anden besked m2, sådan at hash(m1) = hash(m2).
  Sådan tændes Microsoft Outlook Dark Mode

Pythons hashlib-modul

Pythons indbyggede hashlib-modul giver implementeringer af adskillige hashing- og beskedsammenslutningsalgoritmer, inklusive SHA- og MD5-algoritmerne.

For at bruge konstruktørerne og de indbyggede funktioner fra Python hashlib-modulet kan du importere det til dit arbejdsmiljø sådan:

import hashlib

Hashlib-modulet giver konstanterne algorithms_available og algorithms_guaranteed, som angiver det sæt af algoritmer, hvis implementeringer er tilgængelige og er garanteret på en platform, henholdsvis.

Derfor er algorithms_guaranteed en delmængde af algorithms_available.

Start en Python REPL, importer hashlib og få adgang til konstanterne algorithms_available og algorithms_guaranteed:

>>> hashlib.algorithms_available
# Output
{'md5', 'md5-sha1', 'sha3_256', 'shake_128', 'sha384', 'sha512_256', 'sha512', 'md4', 
'shake_256', 'whirlpool', 'sha1', 'sha3_512', 'sha3_384', 'sha256', 'ripemd160', 'mdc2', 
'sha512_224', 'blake2s', 'blake2b', 'sha3_224', 'sm3', 'sha224'}
>>> hashlib.algorithms_guaranteed
# Output
{'md5', 'shake_256', 'sha3_256', 'shake_128', 'blake2b', 'sha3_224', 'sha3_384', 
'sha384', 'sha256', 'sha1', 'sha3_512', 'sha512', 'blake2s', 'sha224'}

Vi ser, at algorithms_guaranteed faktisk er en delmængde af algorithms_available

Sådan opretter du Hash-objekter i Python

Lad os derefter lære, hvordan man opretter hash-objekter i Python. Vi beregner SHA256-hashen for en meddelelsesstreng ved hjælp af følgende metoder:

  • Den generiske new()-konstruktør
  • Algoritme-specifikke konstruktører

Brug af den nye() Constructor

Lad os initialisere meddelelsesstrengen:

>>> message = "toadmin.dk is awesome!"

For at instantiere hash-objektet kan vi bruge new()-konstruktøren og indsætte navnet på algoritmen som vist:

>>> sha256_hash = hashlib.new("SHA256")

Vi kan nu kalde update()-metoden på hash-objektet med meddelelsesstrengen som argument:

>>> sha256_hash.update(message)

Hvis du gør det, vil du løbe ind i en fejl, da hashing-algoritmer kun kan fungere med byte-strenge.

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Unicode-objects must be encoded before hashing

For at få den kodede streng kan du kalde encode()-metoden på metodestrengen og derefter bruge den i update()-metodekaldet. Efter at have gjort det, kan du kalde hexdigest()-metoden for at få sha256-hash, der svarer til meddelelsesstrengen.

sha256_hash.update(message.encode())
sha256_hash.hexdigest()
# Output:'b360c77de704ad8f02af963d7da9b3bb4e0da6b81fceb4c1b36723e9d6d9de3d'

I stedet for at kode meddelelsesstrengen ved hjælp af encode() metoden, kan du også definere den som en streng af bytes ved at præfiksere strengen med b sådan:

message = b"toadmin.dk is awesome!"
sha256_hash.update(message)
sha256_hash.hexdigest()
# Output: 'b360c77de704ad8f02af963d7da9b3bb4e0da6b81fceb4c1b36723e9d6d9de3d'

Den opnåede hash er den samme som tidligere hash, hvilket bekræfter den deterministiske karakter af hashfunktioner.

  Sådan finder du modelnummeret på en bærbar computer

Derudover skulle en lille ændring i meddelelsesstrengen få hashen til at ændre sig drastisk (også kendt som “lavineeffekt”).

For at bekræfte dette, lad os ændre ‘a’et i ‘awesome’ til ‘A’ og beregne hashen:

message = "toadmin.dk is Awesome!"
h1 = hashlib.new("SHA256")
h1.update(message.encode())
h1.hexdigest()
# Output: '3c67f334cc598912dc66464f77acb71d88cfd6c8cba8e64a7b749d093c1a53ab'

Vi ser, at hashen ændrer sig fuldstændigt.

Brug af den algoritmespecifikke konstruktør

I det foregående eksempel brugte vi den generiske new()-konstruktør og sendte “SHA256” som navnet på algoritmen til at oprette hash-objektet.

I stedet for at gøre det kan vi også bruge sha256()-konstruktøren som vist:

sha256_hash = hashlib.sha256()
message= "toadmin.dk is awesome!"
sha256_hash.update(message.encode())
sha256_hash.hexdigest()
# Output: 'b360c77de704ad8f02af963d7da9b3bb4e0da6b81fceb4c1b36723e9d6d9de3d'

Output-hashen er identisk med den hash, vi fik tidligere for meddelelsesstrengen “toadmin.dk is awesome!”.

Udforskning af attributterne for Hash-objekter

Hash-objekterne har et par nyttige egenskaber:

  • Attributten digest_size angiver størrelsen af ​​digest i bytes. For eksempel returnerer SHA256-algoritmen en 256-bit hash, hvilket svarer til 32 bytes
  • Block_size-attributten refererer til den blokstørrelse, der bruges i hashing-algoritmen.
  • Navneattributten er navnet på den algoritme, som vi kan bruge i new()-konstruktøren. Det kan være nyttigt at slå værdien af ​​denne attribut op, når hash-objekterne ikke har beskrivende navne.

Vi kan kontrollere disse attributter for sha256_hash-objektet, vi oprettede tidligere:

>>> sha256_hash.digest_size
32
>>> sha256_hash.block_size
64
>>> sha256_hash.name
'sha256'

Lad os derefter se på nogle interessante applikationer til hashing ved hjælp af Pythons hashlib-modul.

Praktiske eksempler på hashing

Verifikation af integritet af software og filer

Som udviklere downloader og installerer vi softwarepakker hele tiden. Dette gælder, uanset om du arbejder på Linux-distroen eller på en Windows eller en Mac.

Nogle spejle til softwarepakker er dog muligvis ikke troværdige. Du kan finde hashen (eller checksum) ved siden af ​​downloadlinket. Og du kan verificere integriteten af ​​den downloadede software ved at beregne hashen og sammenligne den med den officielle hash.

  Hvad betyder "HMU", og hvordan bruger du det?

Dette kan også anvendes på filer på din maskine. Selv den mindste ændring i filindhold vil ændre hashen drastisk, du kan tjekke om en fil er blevet ændret ved at verificere hashen.

Her er et simpelt eksempel. Opret en tekstfil ‘my_file.txt’ i arbejdsmappen, og tilføj noget indhold til den.

$ cat my_file.txt
This is a sample text file.
We are  going to compute the SHA256 hash of this text file and also
check if the file has been modified by
recomputing the hash.

Du kan derefter åbne filen i læse binær tilstand (‘rb’), læse indholdet af filen og beregne SHA256 hashen som vist:

>>> import hashlib
>>> with open("my_file.txt","rb") as file:
...     file_contents = file.read()
...     sha256_hash = hashlib.sha256()
...     sha256_hash.update(file_contents)
...     original_hash = sha256_hash.hexdigest()

Her er variablen original_hash hashen af ​​’my_file.txt’ i dens nuværende tilstand.

>>> original_hash
# Output: '53bfd0551dc06c4515069d1f0dc715d002d451c8799add29f3e5b7328fda9f8f'

Rediger nu filen ‘my_file.txt’. Du kan fjerne det ekstra indledende mellemrum før ordet ‘igangværende’. 🙂

Beregn hashen igen og gem den i computed_hash-variablen.

>>> import hashlib
>>> with open("my_file.txt","rb") as file:
...     file_contents = file.read()
...     sha256_hash = hashlib.sha256()
...     sha256_hash.update(file_contents)
...     computed_hash = sha256_hash.hexdigest()

Du kan derefter tilføje en simpel assert-sætning, der hævder, om computed_hash er lig med original_hash.

>>> assert computed_hash == original_hash

Hvis filen er ændret (hvilket er sandt i dette tilfælde), bør du få en AssertionError:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

Du kan bruge hashing, når du gemmer følsomme oplysninger, såsom adgangskoder i databaser. Du kan også bruge hashing i adgangskodegodkendelse, når du opretter forbindelse til databaser. Valider hash for den indtastede adgangskode i forhold til hash for den korrekte adgangskode.

Konklusion

Jeg håber, at denne vejledning hjalp dig med at lære om generering af sikre hashes med Python. Her er de vigtigste takeaways:

  • Pythons hashlib-modul giver klar-til-brug implementeringer af flere hashing-algoritmer. Du kan få listen over garanterede algoritmer på din platform ved hjælp af hashlib.algorithms_guaranteed.
  • For at oprette et hash-objekt kan du bruge den generiske new()-konstruktør med syntaksen: hashlib.new(“algo-name”). Alternativt kan du bruge konstruktørerne, der svarer til de specifikke hashing-algoritmer, som f.eks. hashlib.sha256() til SHA 256-hash.
  • Efter initialisering af meddelelsesstrengen, der skal hash, og hash-objektet, kan du kalde update()-metoden på hash-objektet, efterfulgt af hexdigest()-metoden for at hente hashen.
  • Hashing kan være praktisk, når man kontrollerer integriteten af ​​softwareartefakter og filer, gemmer følsomme oplysninger i databaser og mere.

Lær derefter, hvordan du koder en tilfældig adgangskodegenerator i Python.