
このチュートリアルでは、Python の hashlib モジュールの組み込み機能を使用して安全なハッシュを作成する方法を説明します。
ハッシュの重要性と安全なハッシュをプログラムで計算する方法を理解することは、アプリケーションのセキュリティに携わっていない場合でも役立ちます。 しかし、なぜ?
Python プロジェクトに取り組んでいると、パスワードやその他の機密情報をデータベースやソース コード ファイルに保存することに懸念を抱くケースに遭遇する可能性があります。 このような場合は、機密情報に対してハッシュ アルゴリズムを実行し、情報の代わりにハッシュを保存する方が安全です。
このガイドでは、ハッシュとは何か、および暗号化との違いについて説明します。 安全なハッシュ関数のプロパティについても説明します。 次に、一般的なハッシュ アルゴリズムを使用して、Python で平文のハッシュを計算します。 これを行うには、組み込みの hashlib モジュールを使用します。
始めましょう!
ハッシングとは?
ハッシュのプロセスは、メッセージ文字列を取り込み、ハッシュと呼ばれる固定長の出力を提供します。 つまり、特定のハッシュ アルゴリズムの出力ハッシュの長さは、入力の長さに関係なく固定されています。 しかし、暗号化とはどう違うのでしょうか?
暗号化では、暗号化された出力を提供する暗号化アルゴリズムを使用して、メッセージまたはプレーン テキストが暗号化されます。 次に、暗号化された出力に対して復号化アルゴリズムを実行して、メッセージ文字列を取得できます。
ただし、ハッシュの動作は異なります。 暗号化のプロセスは、暗号化されたメッセージから暗号化されていないメッセージに、またはその逆に移動できるという点で、元に戻すことができることを学びました。
暗号化とは異なり、ハッシュは可逆プロセスではありません。つまり、ハッシュから入力メッセージに進むことはできません。
ハッシュ関数の性質
ハッシュ関数が満たすべきいくつかのプロパティを簡単に説明しましょう。
- 決定論的: ハッシュ関数は決定論的です。 メッセージ m が与えられた場合、m のハッシュは常に同じです。
- Preimage Resistant: ハッシュは元に戻せない操作ではないと述べたときに、これについては既に説明しました。 プリイメージ耐性プロパティは、出力ハッシュからメッセージ m を見つけることは実行不可能であると述べています。
- 衝突耐性: m1 のハッシュが m2 のハッシュと等しくなるように、2 つの異なるメッセージ文字列 m1 と m2 を見つけることは困難 (または計算上不可能) です。 この性質を耐衝突性といいます。
- Second Preimage Resistant: これは、メッセージ m1 と対応するハッシュ m2 が与えられた場合、hash(m1) = hash(m2) のような別のメッセージ m2 を見つけることができないことを意味します。
Python の hashlib モジュール
Python の組み込み hashlib モジュールは、SHA および MD5 アルゴリズムを含む、いくつかのハッシュおよびメッセージ ダイジェスト アルゴリズムの実装を提供します。
Python hashlib モジュールのコンストラクターと組み込み関数を使用するには、次のように作業環境にインポートできます。
import hashlib
hashlib モジュールは、algorithms_available および algorithm_guaranteed 定数を提供します。これらは、それぞれプラットフォームで実装が利用可能で保証されているアルゴリズムのセットを示します。
したがって、algorithms_guaranteed は algorithm_available のサブセットです。
Python REPL を開始し、hashlib をインポートして、algorithms_available および 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'}
algorithm_guaranteed は実際に algorithm_available のサブセットであることがわかります
Python でハッシュ オブジェクトを作成する方法
次に、Python でハッシュ オブジェクトを作成する方法を学びましょう。 次のメソッドを使用して、メッセージ文字列の SHA256 ハッシュを計算します。
- ジェネリック new() コンストラクター
- アルゴリズム固有のコンストラクター
new() コンストラクターの使用
メッセージ文字列を初期化しましょう:
>>> message = "etechjp.com is awesome!"
ハッシュ オブジェクトをインスタンス化するには、new() コンストラクターを使用して、次のようにアルゴリズムの名前を渡します。
>>> sha256_hash = hashlib.new("SHA256")
メッセージ文字列を引数として、ハッシュ オブジェクトで update() メソッドを呼び出すことができます。
>>> sha256_hash.update(message)
これを行うと、ハッシュ アルゴリズムはバイト文字列でしか機能しないため、エラーが発生します。
Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: Unicode-objects must be encoded before hashing
エンコードされた文字列を取得するには、メソッド文字列に対して encode() メソッドを呼び出し、それを update() メソッド呼び出しで使用します。 その後、hexdigest() メソッドを呼び出して、メッセージ文字列に対応する sha256 ハッシュを取得できます。
sha256_hash.update(message.encode()) sha256_hash.hexdigest() # Output:'b360c77de704ad8f02af963d7da9b3bb4e0da6b81fceb4c1b36723e9d6d9de3d'
encode() メソッドを使用してメッセージ文字列をエンコードする代わりに、次のように文字列の前に b を付けることで、メッセージ文字列をバイト文字列として定義することもできます。
message = b"etechjp.com is awesome!" sha256_hash.update(message) sha256_hash.hexdigest() # Output: 'b360c77de704ad8f02af963d7da9b3bb4e0da6b81fceb4c1b36723e9d6d9de3d'
得られたハッシュは前のハッシュと同じであり、ハッシュ関数の決定論的性質を裏付けています。
さらに、メッセージ文字列の小さな変更により、ハッシュが大幅に変更されます (「雪崩効果」とも呼ばれます)。
これを確認するために、「awesome」の「a」を「A」に変更して、ハッシュを計算してみましょう。
message = "etechjp.com is Awesome!" h1 = hashlib.new("SHA256") h1.update(message.encode()) h1.hexdigest() # Output: '3c67f334cc598912dc66464f77acb71d88cfd6c8cba8e64a7b749d093c1a53ab'
ハッシュが完全に変更されていることがわかります。
アルゴリズム固有のコンストラクターの使用
前の例では、汎用の new() コンストラクターを使用し、ハッシュ オブジェクトを作成するアルゴリズムの名前として「SHA256」を渡しました。
そうする代わりに、示されているように sha256() コンストラクターを使用することもできます。
sha256_hash = hashlib.sha256() message= "etechjp.com is awesome!" sha256_hash.update(message.encode()) sha256_hash.hexdigest() # Output: 'b360c77de704ad8f02af963d7da9b3bb4e0da6b81fceb4c1b36723e9d6d9de3d'
出力ハッシュは、メッセージ文字列「etechjp.com is awesome!」に対して以前に取得したハッシュと同じです。
ハッシュ オブジェクトの属性の調査
ハッシュ オブジェクトには、いくつかの便利な属性があります。
- digest_size 属性は、ダイジェストのサイズをバイト単位で示します。 たとえば、SHA256 アルゴリズムは 256 ビットのハッシュを返します。これは 32 バイトに相当します。
- block_size 属性は、ハッシュ アルゴリズムで使用されるブロック サイズを参照します。
- name 属性は、 new() コンストラクターで使用できるアルゴリズムの名前です。 この属性の値を調べると、ハッシュ オブジェクトにわかりやすい名前がない場合に役立ちます。
以前に作成した sha256_hash オブジェクトのこれらの属性を確認できます。
>>> sha256_hash.digest_size 32 >>> sha256_hash.block_size 64 >>> sha256_hash.name 'sha256'
次に、Python の hashlib モジュールを使用したハッシュの興味深いアプリケーションを見てみましょう。
ハッシングの実例
ソフトウェアとファイルの整合性の検証
開発者として、私たちは常にソフトウェア パッケージをダウンロードしてインストールしています。 これは、Linux ディストリビューションで作業しているか、Windows または Mac で作業しているかに関係なく当てはまります。
ただし、ソフトウェア パッケージの一部のミラーは信頼できない場合があります。 ダウンロード リンクの横にハッシュ (またはチェックサム) があります。 また、ハッシュを計算して公式のハッシュと比較することで、ダウンロードしたソフトウェアの整合性を検証できます。
これは、マシン上のファイルにも適用できます。 ファイルの内容がわずかに変更されただけでも、ハッシュは大幅に変更されます。ハッシュを検証することで、ファイルが変更されたかどうかを確認できます。
簡単な例を次に示します。 作業ディレクトリにテキスト ファイル「my_file.txt」を作成し、コンテンツを追加します。
$ 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.
次に、読み取りバイナリ モード (「rb」) でファイルを開き、ファイルの内容を読み取り、次のように SHA256 ハッシュを計算します。
>>> 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()
ここで、変数 original_hash は、現在の状態での「my_file.txt」のハッシュです。
>>> original_hash # Output: '53bfd0551dc06c4515069d1f0dc715d002d451c8799add29f3e5b7328fda9f8f'
ここで、ファイル ‘my_file.txt’ を変更します。 「going」という単語の前にある余分な先頭の空白を削除できます。 🙂
ハッシュをもう一度計算して、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()
次に、computed_hash が original_hash と等しいかどうかをアサートする単純な assert ステートメントを追加できます。
>>> assert computed_hash == original_hash
ファイルが変更された場合 (この場合はこれが当てはまります)、AssertionError を取得する必要があります。
Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError
パスワードなどの機密情報をデータベースに保存する場合は、ハッシュを使用できます。 データベースへの接続時に、パスワード認証でハッシュを使用することもできます。 正しいパスワードのハッシュに対して、入力されたパスワードのハッシュを検証します。
結論
このチュートリアルが、Python で安全なハッシュを生成する方法を学ぶのに役立つことを願っています。 主なポイントは次のとおりです。
- Python の hashlib モジュールは、いくつかのハッシュ アルゴリズムのすぐに使用できる実装を提供します。 hashlib.algorithms_guaranteed を使用して、プラットフォームで保証されているアルゴリズムのリストを取得できます。
- ハッシュ オブジェクトを作成するには、汎用の new() コンストラクターを構文 hashlib.new(“algo-name”) で使用できます。 または、SHA 256 ハッシュの hashlib.sha256() のように、特定のハッシュ アルゴリズムに対応するコンストラクタを使用することもできます。
- ハッシュするメッセージ文字列とハッシュ オブジェクトを初期化した後、ハッシュ オブジェクトで update() メソッドを呼び出し、続いて hexdigest() メソッドを呼び出してハッシュを取得できます。
- ハッシュは、ソフトウェアの成果物やファイルの整合性をチェックしたり、機密情報をデータベースに保存したりする場合などに役立ちます。
次に、Python でランダム パスワード ジェネレーターをコーディングする方法を学びます。