Pythonでsecretsモジュールを使ってパスワードを自動生成する
- Pythonでパスワード作るには
secrets.choice()
を使った方が良いと言われているけど、random.choice()
と何が違うのか? random.choice()
で作成されたパスワードは予測される可能性がある。パスワードを構成するすべての文字がランダムに選ばれたように見えて実はどんな文字が選ばれているのかを第三者が計算することができる。 対して、secrets.choice()
はより予測が難しくなったもの。
注意事項
secrets
モジュールはより安全であると紹介しているサイトを見かけますが、PEP506のQ/Aに「専用の暗号化ソフトウェアの代用にはならない」との記述があります。過度な信頼をしてはいけないと私は解釈しました。
この記事はrandom.choice()
よりはsecrets.choice()
のほうがベターだよね、ということをお伝えするのが目的であり、安全であるとお伝えする意図は一切ありません。ご使用は自己責任でお願いします。
解説
random.choice()
random.Randomクラスの関数であり、Mersenne Twisterという乱数発生器(アルゴリズム)を使用しているが、暗号化の目的には向いていない。
実は、random
モジュールは別に random.SystemRandomクラス も提供していて、このクラスはOSがもつ乱数発生器を利用して乱数を作成する。
secrets.choice()
secrets.SystemRandomクラスの関数であり、このクラスもOSがもつ乱数発生器を利用して乱数を作成する。
サンプルプログラム
アルファベットの大文字と小文字、数字0~9の中から10文字をランダムに選びパスワードを作成する。そして、パスワードをクリップボードにコピーし、念のためテキストファイル(.txt)にしてデスクトップにも保存する。というプログラム。
import os import datetime import string import secrets import ctypes import pyperclip #Determine password length len_pw = 10 #Create password def create_pw(length): chars = string.ascii_uppercase + string.ascii_lowercase + string.digits pw = ''.join([secrets.choice(chars) for i in range(length)]) return pw #Save as txt def save_txt(password): now = datetime.datetime.now() filename = "PassWord_{:%Y%m%d%H%M%S}.txt".format(now) desktop = os.getenv("HOMEDRIVE") + os.getenv("HOMEPATH") + "\\Desktop" with open(os.path.join(desktop, filename), mode='a') as f: f.write(password) def main(): x = create_pw(len_pw) save_txt(x) pyperclip.copy(x) ctypes.windll.user32.MessageBoxW( 0, "パスワードをクリップボードにコピーしました", "Complete!!", 0x00000040) if __name__ == '__main__': main()