mei_13のPython講座 ロゴ

【解説】安全なパスワード生成の鍵:Python "secrets" モジュール徹底解説




🐍 初心者歓迎!月額4,000円で質問し放題のPython講座
(1時間4,000円の伴走型ビデオチャット指導も受付中!)
🚀 講座の詳細を見る 📩 質問・お問い合わせ

安全なパスワード生成の鍵:Python "secrets" モジュール徹底解説


Yukiのアイコン
【Yuki】 Hirokiくん、こんにちは。今日はPythonで「セキュリティ」に関わる、とても大切なお話をしようと思います。プログラミングをしていると、ランダムな数字や文字列を作りたい場面がよくありますよね。でも、その使い道を間違えると、少し危ないことになってしまうかもしれないんです……。


Hirokiのアイコン
【Hiroki】 Yukiさん、こんにちは!ランダムな値、よく使います。ゲームのサイコロの目を作るときに import random を使って random.randint() とかを使っています。それが危ないってことですか……?


Yukiのアイコン
【Yuki】 そうですね、ゲームなら問題ないのですが……もしそれが「パスワード」や「認証用のトークン」を作るためのものだとしたら、random モジュールは使わないほうがいいんです。今回は、セキュリティのために用意された "secrets" モジュール について、一緒に学んでいきましょう。

なぜ "random" ではいけないのか


Yukiのアイコン
【Yuki】 まず、なぜ random モジュールがセキュリティに向かないのかをお話ししますね。random モジュールで生成される乱数は「擬似乱数」と呼ばれていて、実は「決定論的」なアルゴリズムに基づいています。


Hirokiのアイコン
【Hiroki】 決定論的……? つまり、予測ができるってことですか?


Yukiのアイコン
【Yuki】 ええ、その通りです。random モジュールは「メルセンヌ・ツイスタ」というアルゴリズムを使っているのですが、これは生成された値をいくつか観察していると、次に出る値を高い確率で予測できてしまうという性質があるんです。悪い人がそれを解析したら、ユーザーのパスワードや秘密のURLを言い当てられてしまうかもしれません……。


Hirokiのアイコン
【Hiroki】 それは怖いですね。ゲームのアイテムドロップなら予測されても致命的ではないですけど、銀行の暗証番号やログインパスワードがバレたら大変です。


Yukiのアイコン
【Yuki】 そうなんです。だからこそ、Python 3.6から "secrets" モジュール が導入されました。このモジュールは、OSが提供する「より安全な乱数生成器」を使っていて、予測が極めて困難なようになっています。これを「暗号論的な擬似乱数生成器(CSPRNG)」と呼びます。

secrets モジュールの基本的な使い方


Yukiのアイコン
【Yuki】 では、実際に secrets を使ってみましょう。まずは、リストの中から要素をランダムに選ぶ方法です。random.choice() と使い方は似ていますが、中身の安全性は全然違います。


Hirokiのアイコン
【Hiroki】 使い方が似ているなら、僕でもすぐに覚えられそうです!


Yukiのアイコン
【Yuki】 そう言ってもらえると嬉しいです。まずはコードを書いてみますね。

import secrets
import string

# パスワードに使う文字の候補を定義します
alphabet = string.ascii_letters + string.digits

# リストから1つ安全に選択します
password_char = secrets.choice(alphabet)
print(f"選ばれた文字: {password_char}")


Hirokiのアイコン
【Hiroki】 本当だ、random.choice() と同じ感覚で使えますね。これなら、Webサービスで仮パスワードを発行するときなんかに役立ちそうです。


Yukiのアイコン
【Yuki】 ええ、その通りだと思います。さらに、特定の範囲の数字を生成するときは secrets.randbelow() を使います。

# 0以上100未満の整数を安全に生成します
number = secrets.randbelow(100)
print(f"安全な数値: {number}")


Hirokiのアイコン
【Hiroki】 random.randint(0, 99) みたいな感じですね。でも、randbelow(100) の方が「100未満」というのが直感的で分かりやすい気がします。

セキュリティトークンの生成


Yukiのアイコン
【Yuki】 ここからは、より実践的な使い方を見ていきましょう。Web開発などをしていると、ユーザーのメールアドレス確認用URLや、APIキーのような「トークン」が必要になることがありますよね。


Hirokiのアイコン
【Hiroki】 はい!よくメールで送られてくる「こちらのリンクをクリックして登録を完了してください」というURLの末尾についている、長い英数字のことですよね。


Yukiのアイコン
【Yuki】 そうです。あのような文字列を生成するために、secrets には専用の関数が用意されています。代表的なものを2つ紹介しますね。

# 16進数の文字列を生成します(引数はバイト数です)
token_hex = secrets.token_hex(16)
print(f"16進数トークン: {token_hex}")

# URLに適した文字列を生成します(Base64エンコード)
token_url = secrets.token_urlsafe(16)
print(f"URL用トークン: {token_url}")


Hirokiのアイコン
【Hiroki】 へぇ!token_urlsafe() って便利ですね。Base64っていうと、記号とかも混ざるイメージですけど、URLで使っても大丈夫なんですか?


Yukiのアイコン
【Yuki】 はい。token_urlsafe() は、URLの中で特別な意味を持ってしまう記号(「/」や「+」など)を、安全な記号に置き換えてくれるんです。わたしもWebの仕組みを考えるとき、この関数にはいつも助けられています……。


Hirokiのアイコン
【Hiroki】 なるほど。自分で変換処理を書かなくていいのは、ミスも減らせて安心ですね。

実践:安全なパスワード生成器を作ってみる


Yukiのアイコン
【Yuki】 せっかくなので、これまでの知識を組み合わせて「安全なパスワード生成器」の関数を作ってみましょう。Hirokiくん、どんなルールで作りたいですか?


Hirokiのアイコン
【Hiroki】 えーっと、英大文字、英小文字、数字、あと記号が最低1つは入っている、8文字以上のパスワードがいいです!


Yukiのアイコン
【Yuki】 いい条件ですね。それを実現するには、単純にループで secrets.choice() を使うだけではなく、条件を満たすまで繰り返すような工夫が必要になるかもしれません。少し複雑ですが、一緒に見てみましょう。

import secrets
import string

def generate_secure_password(length=12):
    if length < 8:
        return "パスワードは8文字以上を推奨します"

    # 使用する文字のセット
    alphabet = string.ascii_letters + string.digits + string.punctuation

    while True:
        # 指定された長さのパスワードを生成
        password = ''.join(secrets.choice(alphabet) for _ in range(length))

        # 条件を満たしているかチェック
        # (少なくとも1つの小文字、大文字、数字、記号が含まれているか)
        if (any(c.islower() for c in password)
                and any(c.isupper() for c in password)
                and any(c.isdigit() for c in password)
                and any(c in string.punctuation for c in password)):
            return password

# 実行
new_password = generate_secure_password(16)
print(f"生成されたパスワード: {new_password}")


Hirokiのアイコン
【Hiroki】 おお……! while True で、条件を満たすまで作り直しているんですね。secrets.choice を使っているから、一つ一つの文字が予測されにくいし、全体としても強固なパスワードになりそうです。


Yukiのアイコン
【Yuki】 はい。このように、「絶対に予測されてはいけないもの」を作るときは、secrets を使うのが今のPythonの標準なんです。

タイミング攻撃を防ぐ "compare_digest"


Yukiのアイコン
【Yuki】 最後にもう一つ、少し高度な機能を教えますね。パスワードを確認するとき、普通は if input_password == saved_password: のように書くと思います。でも、実はこれすらも、厳密にはセキュリティリスクになることがあるんです。


Hirokiのアイコン
【Hiroki】 ええっ! 文字列を比べるだけでリスクになるんですか?


Yukiのアイコン
【Yuki】 「タイミング攻撃」という手法があるんです。文字列の比較(==)は、左から順番に文字をチェックしていって、違う文字が見つかった瞬間に「偽」と判断して処理を終えます。つまり、「最初の1文字目が合っている場合」と「全く合っていない場合」では、処理が終わるまでの時間に、ごくごく僅かな差が出るんです。


Hirokiのアイコン
【Hiroki】 その僅かな時間の差を測って、パスワードを推測しちゃうってことですか……? 人間の感覚では無理でも、コンピュータならできちゃいそうですね。


Yukiのアイコン
【Yuki】 その通りです。それを防ぐために、secrets.compare_digest() という関数があります。これは、内容がどうであれ、常に同じ時間をかけて比較を行ってくれるんです。

# 秘密のトークンを安全に比較します
actual_token = "secret-api-key-12345"
user_input = "secret-api-key-12345"

if secrets.compare_digest(actual_token, user_input):
    print("認証成功です")
else:
    print("認証失敗です")


Hirokiのアイコン
【Hiroki】 なるほど……。セキュリティの世界って、本当に奥が深いんですね。ただランダムにするだけじゃなくて、比べる時まで気を配る必要があるなんて。


Yukiのアイコン
【Yuki】 そうですね。わたしも、こういう細かい配慮が積み重なって、誰かの大切なデータを守っているんだと思うと、なんだか少し誇らしい気持ちになります……。

まとめ


Yukiのアイコン
【Yuki】 今日のまとめです。 1. セキュリティに関わる用途(パスワード、トークン、秘密のURLなど)には、random ではなく必ず secrets を使うこと。 2. secrets.choice()secrets.randbelow() で安全な値を選べる。 3. secrets.token_hex()secrets.token_urlsafe() は、APIキーやURL用トークンの生成に最適。 4. 文字列の比較には、タイミング攻撃を防ぐ secrets.compare_digest() を検討する。

もっと詳しく知りたいときは、公式ドキュメントを見てみてくださいね。 Python 公式ドキュメント: secrets --- 機密を扱うための安全な乱数を生成する


Hirokiのアイコン
【Hiroki】 ありがとうございます!これからは、使い道に合わせて randomsecrets をしっかり使い分けようと思います。Yukiさん、今日も丁寧に教えてくれてありがとうございました!


Yukiのアイコン
【Yuki】 どういたしまして。Hirokiくんがセキュリティに興味を持ってくれて嬉しいです。また分からないことがあったら、いつでも聞いてくださいね……。夜の方が、わたしもゆっくりお話しできるかもしれません。


Hirokiのアイコン
【Hiroki】 はい!またよろしくお願いします!



< データ型
コラム一覧に戻る
MediaPipe >

この記事では基礎を解説しましたが、実務においては「もっと複雑なデータを扱いたい」「独自のシステムに組み込みたい」といった、個別の課題に直面することも多いはずです。

「自分で書く時間は最小限に抑え、プロの品質でツールを完成させたい」という方は、ぜひ一度ご相談ください。

「教わる」だけでなく「形にする」パートナーとして、フリーランスエンジニアのmei_13が最短ルートでの解決をサポートします。

➡ ココナラで制作・相談を依頼する(見積もり無料)


初心者から始められるPythonレッスン

プログラミング未経験者・初心者歓迎!
月額4,000円で質問し放題!!
● 完全オンライン
● 翌日までには必ず返信
● 挫折しない独自の学習メソッド
● 圧倒的高評価!!
テキストベースで時間を選ばない
4,000円/60分伴走型ビデオチャット指導も可能
● 高品質なサンプルコード
詳細はこちら

📩 質問・お問い合わせはこちら



AIアシスタント Yuki