Bezpečné hašování pomocí Pythonu Hashlib

Tento tutoriál vás naučí, jak vytvořit bezpečné hash pomocí vestavěné funkce z modulu hashlib Pythonu.

Pochopení významu hashování a toho, jak programově vypočítat zabezpečené hodnoty hash, může být užitečné – i když nepracujete v zabezpečení aplikací. Ale proč?

Při práci na projektech Pythonu pravděpodobně narazíte na případy, kdy vás znepokojuje ukládání hesel a dalších citlivých informací do databází nebo souborů zdrojového kódu. V takových případech je bezpečnější spustit hashovací algoritmus na citlivých informacích a uložit hash místo informací.

V této příručce se budeme zabývat tím, co je hashování a jak se liší od šifrování. Projdeme si také vlastnosti bezpečných hashovacích funkcí. Potom použijeme běžné hashovací algoritmy k výpočtu hash prostého textu v Pythonu. K tomu použijeme vestavěný modul hashlib.

Pro tohle všechno a ještě víc pojďme začít!

Co je hashování?

Proces hašování zahrnuje řetězec zprávy a poskytuje výstup s pevnou délkou nazývaný hash. To znamená, že délka výstupního hash pro daný hashovací algoritmus je pevná – bez ohledu na délku vstupu. Ale jak se liší od šifrování?

Při šifrování je zpráva nebo prostý text zašifrován pomocí šifrovacího algoritmu, který poskytuje zašifrovaný výstup. Poté můžeme spustit dešifrovací algoritmus na zašifrovaném výstupu a získat zpět řetězec zprávy.

Hašování však funguje jinak. Právě jsme se dozvěděli, že proces šifrování je nevratný v tom, že můžete přejít od zašifrované zprávy k nezašifrované zprávě a naopak.

Na rozdíl od šifrování není hašování nevratný proces, což znamená, že nemůžeme přejít od haše ke vstupní zprávě.

Vlastnosti hashovacích funkcí

Pojďme si rychle projít některé vlastnosti, které by hashovací funkce měly splňovat:

  • Deterministické: Hashovací funkce jsou deterministické. Vzhledem ke zprávě m je hash m vždy stejný.
  • Preimage Resistant: Už jsme to probrali, když jsme řekli, že hašování není nevratná operace. Vlastnost odporu předobrazu uvádí, že je nemožné najít zprávu m z výstupního hashe.
  • Odolnost proti kolizi: Mělo by být obtížné (nebo výpočetně neproveditelné) najít dva různé řetězce zpráv m1 a m2 tak, aby se hash m1 rovnal hash m2. Tato vlastnost se nazývá odolnost proti kolizi.
  • Second Preimage Resistant: To znamená, že po zprávě m1 a odpovídajícím hash m2 je nemožné najít další zprávu m2 tak, že hash(m1) = hash(m2).
  Používejte Google Hangouts jako samostatnou aplikaci Chrome pro stolní počítače

Modul hashlib Pythonu

Vestavěný modul hashlib v Pythonu poskytuje implementace několika algoritmů hashování a zpracování zpráv, včetně algoritmů SHA a MD5.

Chcete-li použít konstruktory a vestavěné funkce z modulu hashlib Pythonu, můžete jej importovat do svého pracovního prostředí takto:

import hashlib

Modul hashlib poskytuje konstanty algorithms_available a algorithms_guaranteed, které označují sadu algoritmů, jejichž implementace jsou dostupné a jsou zaručeny na platformě.

Proto je algorithms_guaranteed podmnožinou algorithms_available.

Spusťte Python REPL, importujte hashlib a získejte přístup ke konstantám algorithms_available a 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'}

Vidíme, že algorithms_guaranteed je skutečně podmnožinou algorithms_available

Jak vytvořit hash objekty v Pythonu

Dále se naučíme, jak vytvořit hash objekty v Pythonu. Hash SHA256 řetězce zprávy vypočítáme pomocí následujících metod:

  • Obecný konstruktor new().
  • Konstruktory specifické pro algoritmus

Pomocí konstruktoru new().

Inicializujeme řetězec zprávy:

>>> message = "etechblog.cz is awesome!"

K vytvoření instance objektu hash můžeme použít konstruktor new() a předat název algoritmu, jak je znázorněno:

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

Nyní můžeme zavolat metodu update() na objektu hash s řetězcem zprávy jako argumentem:

>>> sha256_hash.update(message)

Pokud tak učiníte, narazíte na chybu, protože hashovací algoritmy mohou pracovat pouze s bajtovými řetězci.

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

Chcete-li získat zakódovaný řetězec, můžete na řetězci metody zavolat metodu encode() a poté ji použít ve volání metody update(). Poté můžete zavolat metodu hexdigest() a získat hash sha256 odpovídající řetězci zprávy.

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

Místo kódování řetězce zprávy pomocí metody encode() jej můžete také definovat jako řetězec bajtů tak, že před řetězec přidáte b takto:

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

Získaný hash je stejný jako předchozí hash, což potvrzuje deterministický charakter hashovacích funkcí.

  Jak najít duplicitní hodnoty v aplikaci Microsoft Excel

Malá změna v řetězci zprávy by navíc měla způsobit drastickou změnu hash (známé také jako „lavinový efekt“).

Abychom to ověřili, změňme ‚a‘ v ‚awesome‘ na ‚A‘ a vypočítejme hash:

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

Vidíme, že se hash úplně změní.

Použití konstruktoru specifického pro algoritmus

V předchozím příkladu jsme použili obecný konstruktor new() a předali „SHA256“ jako název algoritmu k vytvoření objektu hash.

Místo toho můžeme také použít konstruktor sha256(), jak je znázorněno:

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

Výstupní hash je identický s hashem, který jsme získali dříve pro řetězec zprávy „etechblog.cz je úžasné!“.

Zkoumání atributů hash objektů

Objekty hash mají několik užitečných atributů:

  • Atribut digest_size udává velikost digestu v bajtech. Například algoritmus SHA256 vrací 256bitový hash, což je ekvivalent 32 bajtů
  • Atribut block_size odkazuje na velikost bloku použitou v hašovacím algoritmu.
  • Atribut name je název algoritmu, který můžeme použít v konstruktoru new(). Vyhledání hodnoty tohoto atributu může být užitečné, když objekty hash nemají popisné názvy.

Můžeme zkontrolovat tyto atributy pro objekt sha256_hash, který jsme vytvořili dříve:

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

Dále se podívejme na některé zajímavé aplikace hašování pomocí modulu hashlib v Pythonu.

Praktické příklady hašování

Ověřování integrity softwaru a souborů

Jako vývojáři neustále stahujeme a instalujeme softwarové balíčky. To platí bez ohledu na to, zda pracujete na distribuci Linuxu nebo na Windows nebo Mac.

Některá zrcadla softwarových balíků však nemusí být důvěryhodná. Hash (nebo kontrolní součet) najdete vedle odkazu ke stažení. Integritu staženého softwaru můžete ověřit výpočtem hashe a jeho porovnáním s oficiálním hashem.

  Jak vytvořit vlastní widgety na iPhone

To lze použít i na soubory ve vašem počítači. I sebemenší změna obsahu souboru drasticky změní hash, můžete zkontrolovat, zda byl soubor změněn, ověřením hashe.

Zde je jednoduchý příklad. Vytvořte textový soubor ‚my_file.txt‘ v pracovním adresáři a přidejte do něj nějaký obsah.

$ 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.

Poté můžete soubor otevřít v binárním režimu čtení (‚rb‘), přečíst obsah souboru a vypočítat hash SHA256, jak je znázorněno:

>>> 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()

Zde je proměnná original_hash hash souboru ‚my_file.txt‘ v aktuálním stavu.

>>> original_hash
# Output: '53bfd0551dc06c4515069d1f0dc715d002d451c8799add29f3e5b7328fda9f8f'

Nyní upravte soubor ‚my_file.txt‘. Můžete odstranit přebytečné mezery na začátku před slovem ‚jít‘. 🙂

Vypočítejte hash ještě jednou a uložte jej do proměnné computed_hash.

>>> 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()

Potom můžete přidat jednoduchý příkaz statement, který potvrdí, pokud se computed_hash rovná původnímu_hash.

>>> assert computed_hash == original_hash

Pokud je soubor změněn (což je v tomto případě pravda), měli byste dostat AssertionError:

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

Hash můžete použít při ukládání citlivých informací, jako jsou hesla v databázích. Při připojování k databázím můžete také použít hash při ověřování heslem. Ověřte hash zadaného hesla proti hash správného hesla.

Závěr

Doufám, že vám tento tutoriál pomohl dozvědět se o generování bezpečných hashů pomocí Pythonu. Zde jsou hlavní poznatky:

  • Modul hashlib Pythonu poskytuje implementace několika hashovacích algoritmů připravené k použití. Seznam zaručených algoritmů na vaší platformě můžete získat pomocí hashlib.algorithms_guaranteed.
  • Chcete-li vytvořit objekt hash, můžete použít obecný konstruktor new() se syntaxí: hashlib.new(“algo-name”). Alternativně můžete použít konstruktory odpovídající konkrétním hašovacím algoritmům, například: hashlib.sha256() pro hash SHA 256.
  • Po inicializaci řetězce zprávy, která má být hašována, a objektu hash můžete zavolat metodu update() na objekt hash a poté metodu hexdigest() a získat hash.
  • Hašování se může hodit při kontrole integrity softwarových artefaktů a souborů, ukládání citlivých informací v databázích a podobně.

Dále se dozvíte, jak kódovat generátor náhodných hesel v Pythonu.