前枠
何か自分で調べて開発してみたかったのと,前からパスワードの生成について興味があったので作ろうということになりました.
私はPython がチョットワカルのでPython ライブラリを使って簡単に作っていきたいと思います.
開発に関しては素人なので,コードが汚いのはご了承ください.
目指す要件
- 最初はクラスにする,最終的にはWebアプリにもしてみたい.
- 文字数の選択ができる
- 含む文字の種類が選択できる
- 「大文字アルファベットが少なくとも1回出てくる」のようなことが選択できる.
まず乱数について調べる
パスワードの大前提として他人に推測されないようなものが推奨されるため,文字をどのように選択していくかが重要.
なので,ランダムに文字を選択してくれる仕組みが必要.
Python にはrandomモジュールがある.
https://docs.python.org/ja/3/library/random.html#module-random
しかし上の公式ドキュメントにある通り,論理的には再現できてしまう・推測できてしまうような,ある程度ランダムな値を導出するに過ぎず,セキュリティ目的には向かない.
そこでセキュリティ目的の利用が推奨されているのが,OSが提供する乱数発生源をもとにしているsecretsモジュール
https://docs.python.org/ja/3/library/secrets.html#module-secrets
これだよ.こういうのでいいんだよ.
しかもよくみると,レシピとベストプラクティスが書いてある.
アルファべットと数字からなり、小文字を少なくとも1つと数字を少なくとも3つ含む、10文字のパスワードを生成するには:
import string
import secrets
alphabet = string.ascii_letters + string.digits
while True:
password = ''.join(secrets.choice(alphabet) for i in range(10))
if (any(c.islower() for c in password)
and any(c.isupper() for c in password)
and sum(c.isdigit() for c in password) >= 3):
break
これをいじっていこう.
関数化する
パスワード長を引数でとる
import string
import secrets
alphabet = string.ascii_letters + string.digits
def password_generater(password_length):
while True:
password = ''.join(secrets.choice(alphabet) for i in range(password_length))
if (any(c.islower() for c in password) and any(c.isupper() for c in password) and sum(c.isdigit() for c in password) >= 3):
break
return password
import generate_random
# 引数でパスワード長を指定できる
result = generate_random.password_generater(16)
print(result)
実行してみると
7g29HnFJItLJoiB7
うん,いい感じ.
各文字の出現の最小数を引数でとる
import string
import secrets
alphabet = string.ascii_letters + string.digits
def password_generater(password_length, lower_letters_min=0, upper_letters_min=0, digit_min=0):
while True:
password = ''.join(secrets.choice(alphabet) for i in range(password_length))
if (sum(c.islower() for c in password) >= lower_letters_min and sum(c.isupper() for c in password) >= upper_letters_min and sum(c.isdigit() for c in password) >= digit_min):
break
return password
デフォルトで0としているので,特に指定がなければ一回で生成される.
実行してみると
zmoIBPQVU8MI3tJL
公式のレシピでの「数字が少なくとも3つ出現」という条件が確かに無くなっていそう.
引数をリストにしてみる
ここまでやってみて,出現数をリストでまとめておいた方が,「大文字アルファベットの最小数のみを指定したい!」みたいなときに便利そうと思いついた.
ひとまず,パスワード長のデフォルト値を設定
import string
import secrets
alphabet = string.ascii_letters + string.digits
def password_generater(password_length=8, lower_letters_min=0, upper_letters_min=0, digit_min=0):
while True:
password = ''.join(secrets.choice(alphabet) for i in range(password_length))
if (sum(c.islower() for c in password) >= lower_letters_min and sum(c.isupper() for c in password) >= upper_letters_min and sum(c.isdigit() for c in password) >= digit_min):
break
return password
if __name__ == "__main__":
print(password_generater())
# 実行結果例
# gTiKxsEj (確かに8文字だし,数字出てなかったりする)
Python の関数は,引数にリストを指定するときに「*」を前に付ければ展開してくれるので,それを使おう.
import generate_random
required_parameter = [16, 3, 3, 3]
result = generate_random.password_generater(*required_parameter)
print(result)
# 実行結果例
# NV03AKUaGdsdG6Hr
いい感じな気がする.
後枠
ひとまず,自分で満足できたので,一区切り.
Webアプリとか,リストの初期化とか気にしなきゃいけないことがありそうなので勉強せねば.