Bu öğretici, size Python’un hashlib modülündeki yerleşik işlevselliği kullanarak güvenli karma oluşturmayı öğretecektir.
Uygulama güvenliğinde çalışmasanız bile, sağlamanın önemini ve güvenli karmaların programlı olarak nasıl hesaplanacağını anlamak yardımcı olabilir. Ama neden?
Pekala, Python projeleri üzerinde çalışırken, veritabanlarında veya kaynak kodu dosyalarında parolaları ve diğer hassas bilgileri depolamaktan endişe duyduğunuz durumlar ile karşılaşacaksınız. Bu gibi durumlarda hashing algoritmasını hassas bilgiler üzerinde çalıştırmak ve bilgi yerine hash’i saklamak daha güvenlidir.
Bu kılavuzda, karma oluşturmanın ne olduğunu ve şifrelemeden nasıl farklı olduğunu ele alacağız. Güvenli hash işlevlerinin özelliklerini de gözden geçireceğiz. Ardından, Python’da düz metnin hash’ini hesaplamak için yaygın hash algoritmalarını kullanacağız. Bunu yapmak için yerleşik hashlib modülünü kullanacağız.
Hepsi ve daha fazlası için haydi başlayalım!
Hashing Nedir?
Karma işlemi, bir mesaj dizisini alır ve karma adı verilen sabit uzunlukta bir çıktı verir. Yani, belirli bir karma algoritma için çıktı karmasının uzunluğu, girdinin uzunluğundan bağımsız olarak sabittir. Ancak şifrelemeden farkı nedir?
Şifrelemede, mesaj veya düz metin, şifrelenmiş bir çıktı veren bir şifreleme algoritması kullanılarak şifrelenir. Daha sonra mesaj dizisini geri almak için şifreli çıktı üzerinde şifre çözme algoritmasını çalıştırabiliriz.
Ancak, karma farklı şekilde çalışır. Şifreli mesajdan şifrelenmemiş mesaja ve tersi yönde gidebileceğiniz için şifreleme işleminin tersine çevrilebilir olduğunu yeni öğrendik.
Şifrelemeden farklı olarak, karma işlemi tersine çevrilebilir bir işlem değildir, yani karmadan giriş mesajına geçemeyiz.
Hash Fonksiyonlarının Özellikleri
Hash fonksiyonlarının karşılaması gereken bazı özellikleri hızlıca gözden geçirelim:
- Deterministik: Hash fonksiyonları deterministiktir. Bir m mesajı verildiğinde, m’nin hash’i her zaman aynıdır.
- Preimage Dirençli: Karma işlemin tersine çevrilebilir bir işlem olmadığını söylediğimizde bunu zaten ele almıştık. Ön görüntü direnci özelliği, çıktı hash’inden m mesajını bulmanın mümkün olmadığını belirtir.
- Çarpışmaya Dayanıklı: m1’in hash’i m2’nin hash’ine eşit olacak şekilde m1 ve m2 iki farklı mesaj dizisini bulmak zor (veya hesaplama açısından mümkün değil) olmalıdır. Bu özelliğe çarpışma direnci denir.
- İkinci Preimage Dirençli: Bu, m1 mesajı ve karşılık gelen hash m2 verildiğinde, hash(m1) = hash(m2) şeklinde başka bir m2 mesajı bulmanın mümkün olmadığı anlamına gelir.
Python’un hashlib Modülü
Python’un yerleşik hashlib modülü, SHA ve MD5 algoritmaları dahil olmak üzere çeşitli karma ve mesaj özet algoritmalarının uygulamalarını sağlar.
Python hashlib modülündeki oluşturucuları ve yerleşik işlevleri kullanmak için, onu şu şekilde çalışma ortamınıza aktarabilirsiniz:
import hashlib
Hashlib modülü, sırasıyla uygulamaları mevcut olan ve bir platformda garantili olan algoritmalar kümesini ifade eden algoritmalar_kullanılabilir ve algoritmalar_garantili sabitleri sağlar.
Bu nedenle, garantili algoritmalar, elde edilebilir algoritmaların bir alt kümesidir.
Bir Python REPL başlatın, hashlib’i içe aktarın ve algoritmalar_kullanılabilir ve algoritmalar_garantili sabitlerine erişin:
>>> 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'}
Algoritmalar_garantili’nin gerçekten de algoritmalar_kullanılabilir’in bir alt kümesi olduğunu görüyoruz.
Python’da Hash Nesneleri Nasıl Oluşturulur
Şimdi Python’da karma nesnelerin nasıl oluşturulacağını öğrenelim. Aşağıdaki yöntemleri kullanarak bir mesaj dizisinin SHA256 karmasını hesaplayacağız:
- Genel new() yapıcısı
- Algoritmaya Özgü Oluşturucular
new() Yapıcısını Kullanma
Mesaj dizisini başlatalım:
>>> message = "trtechpc.eu is awesome!"
Hash nesnesini başlatmak için new() yapıcısını kullanabilir ve algoritmanın adını gösterildiği gibi iletebiliriz:
>>> sha256_hash = hashlib.new("SHA256")
Artık hash nesnesindeki update() yöntemini argüman olarak mesaj dizesiyle çağırabiliriz:
>>> sha256_hash.update(message)
Bunu yaparsanız, karma algoritmalar yalnızca bayt dizileriyle çalışabileceğinden bir hatayla karşılaşırsınız.
Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: Unicode-objects must be encoded before hashing
Kodlanmış dizeyi almak için, yöntem dizesinde encode() yöntemini çağırabilir ve ardından bunu update() yöntem çağrısında kullanabilirsiniz. Bunu yaptıktan sonra, mesaj dizisine karşılık gelen sha256 karmasını almak için hexdigest() yöntemini çağırabilirsiniz.
sha256_hash.update(message.encode()) sha256_hash.hexdigest() # Output:'b360c77de704ad8f02af963d7da9b3bb4e0da6b81fceb4c1b36723e9d6d9de3d'
mesaj dizgisini encode() yöntemini kullanarak kodlamak yerine, dizgenin önüne b ekleyerek şunun gibi bir bayt dizisi olarak da tanımlayabilirsiniz:
message = b"trtechpc.eu is awesome!" sha256_hash.update(message) sha256_hash.hexdigest() # Output: 'b360c77de704ad8f02af963d7da9b3bb4e0da6b81fceb4c1b36723e9d6d9de3d'
Elde edilen hash, hash fonksiyonlarının deterministik doğasını doğrulayan önceki hash ile aynıdır.
Ek olarak, mesaj dizisindeki küçük bir değişiklik, özetin büyük ölçüde değişmesine neden olmalıdır (“çığ etkisi” olarak da bilinir).
Bunu doğrulamak için, ‘awesome’ içindeki ‘a’yı ‘A’ olarak değiştirelim ve hash’i hesaplayalım:
message = "trtechpc.eu is Awesome!" h1 = hashlib.new("SHA256") h1.update(message.encode()) h1.hexdigest() # Output: '3c67f334cc598912dc66464f77acb71d88cfd6c8cba8e64a7b749d093c1a53ab'
Hash’in tamamen değiştiğini görüyoruz.
Algoritmaya Özgü Oluşturucuyu Kullanma
Önceki örnekte, jenerik new() yapıcısını kullandık ve hash nesnesini oluşturmak için algoritmanın adı olarak “SHA256″yı geçtik.
Bunu yapmak yerine, sha256() yapıcısını gösterildiği gibi de kullanabiliriz:
sha256_hash = hashlib.sha256() message= "trtechpc.eu is awesome!" sha256_hash.update(message.encode()) sha256_hash.hexdigest() # Output: 'b360c77de704ad8f02af963d7da9b3bb4e0da6b81fceb4c1b36723e9d6d9de3d'
Çıktı hash’i, daha önce “trtechpc.eu harika!” mesaj dizgisi için elde ettiğimiz hash ile aynıdır.
Karma Nesnelerin Niteliklerini Keşfetmek
Hash nesnelerinin birkaç faydalı özelliği vardır:
- Digest_size niteliği, özetin bayt cinsinden boyutunu belirtir. Örneğin, SHA256 algoritması, 32 bayta eşdeğer olan 256 bitlik bir karma değeri döndürür.
- block_size özniteliği, karma algoritmasında kullanılan blok boyutunu ifade eder.
- name niteliği new() yapıcısında kullanabileceğimiz algoritmanın adıdır. Karma nesnelerin açıklayıcı adları olmadığında bu özniteliğin değerine bakmak yararlı olabilir.
Daha önce oluşturduğumuz sha256_hash nesnesi için şu nitelikleri kontrol edebiliriz:
>>> sha256_hash.digest_size 32 >>> sha256_hash.block_size 64 >>> sha256_hash.name 'sha256'
Ardından, Python’un hashlib modülünü kullanan bazı ilginç karma uygulamalarına bakalım.
Pratik Hashing Örnekleri
Yazılım ve Dosyaların Bütünlüğünü Doğrulama
Geliştiriciler olarak, her zaman yazılım paketlerini indirir ve kurarız. Bu, ister Linux dağıtımında, ister Windows veya Mac’te çalışıyor olun, geçerlidir.
Ancak, yazılım paketleri için bazı aynalar güvenilir olmayabilir. Karmayı (veya sağlama toplamını) indirme bağlantısının yanında bulabilirsiniz. İndirilen yazılımın bütünlüğünü, hash’i hesaplayarak ve resmi hash ile karşılaştırarak doğrulayabilirsiniz.
Bu, makinenizdeki dosyalara da uygulanabilir. Dosya içeriğindeki en küçük değişiklik bile hash’i büyük ölçüde değiştirecektir, hash’i doğrulayarak bir dosyanın değiştirilip değiştirilmediğini kontrol edebilirsiniz.
İşte basit bir örnek. Çalışma dizininde bir ‘my_file.txt’ metin dosyası oluşturun ve buna biraz içerik ekleyin.
$ 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.
Daha sonra dosyayı ikili okuma modunda (‘rb’) açabilir, dosyanın içeriğini okuyabilir ve gösterildiği gibi SHA256 karmasını hesaplayabilirsiniz:
>>> 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()
Burada, original_hash değişkeni, ‘my_file.txt’ dosyasının mevcut durumundaki karmasıdır.
>>> original_hash # Output: '53bfd0551dc06c4515069d1f0dc715d002d451c8799add29f3e5b7328fda9f8f'
Şimdi ‘my_file.txt’ dosyasını değiştirin. ‘Gidiyor’ kelimesinden önceki fazladan boşlukları kaldırabilirsiniz. 🙂
Karmayı bir kez daha hesaplayın ve onu computed_hash değişkeninde saklayın.
>>> 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()
Daha sonra, hesaplanan_hash’in orijinal_hash’e eşit olup olmadığını belirten basit bir iddia ifadesi ekleyebilirsiniz.
>>> assert computed_hash == original_hash
Dosya değiştirilirse (bu durumda doğrudur), bir AssertionError almalısınız:
Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError
Şifreler gibi hassas bilgileri veritabanlarında saklarken karma oluşturmayı kullanabilirsiniz. Karmayı, veritabanlarına bağlanırken parola kimlik doğrulamasında da kullanabilirsiniz. Girilen şifrenin karmasını doğru şifrenin karmasına karşı doğrulayın.
Çözüm
Umarım bu eğitim, Python ile güvenli karmalar oluşturmayı öğrenmenize yardımcı olmuştur. İşte önemli çıkarımlar:
- Python’un hashlib modülü, birkaç karma algoritmanın kullanıma hazır uygulamalarını sağlar. hashlib.algorithms_guaranteed kullanarak platformunuzda garantili algoritmaların listesini alabilirsiniz.
- Bir karma nesne oluşturmak için, genel new() yapıcısını şu sözdizimiyle kullanabilirsiniz: hashlib.new(“algo-name”). Alternatif olarak, SHA 256 hash için hashlib.sha256() gibi belirli hashing algoritmalarına karşılık gelen oluşturucuları kullanabilirsiniz.
- Karma hale getirilecek mesaj dizesini ve hash nesnesini başlattıktan sonra hash nesnesinde update() yöntemini ve ardından hash’i almak için hexdigest() yöntemini çağırabilirsiniz.
- Hashing, yazılım yapılarının ve dosyalarının bütünlüğünü kontrol ederken, hassas bilgileri veritabanlarında depolarken ve daha pek çok şeyde kullanışlı olabilir.
Ardından, Python’da rastgele bir parola oluşturucuyu nasıl kodlayacağınızı öğrenin.