手を振るまもるくんゆるふわサイバーセキュリティ
監視中のまもるくん

ワンタイムパスワード(TOTP)をPythonで実装|Google Authenticatorのしくみ

2026-09-13 ・ 実践

#TOTP#二段階認証#2FA#Python#実践

Google Authenticatorなどが表示する「30秒ごとに変わる6桁コード」——あれが TOTP(時間ベースのワンタイムパスワード) です。多要素認証の主役を、Pythonの標準ライブラリだけで実装します。仕組みは驚くほどシンプルで、作ると腑に落ちます。

しくみ:秘密鍵 × 時刻

TOTPは「サーバーとアプリで共有した秘密鍵」と「現在時刻(30秒単位)」をHMACにかけ、そこから6桁を取り出すだけ。同じ鍵と同じ時間帯なら、両者は同じコードに必ずたどり着きます。

鍵と時刻から6桁

🔑

共有の秘密鍵

登録時に配布

→
⏱️

30秒枠の時刻

両者で一致

→
🔢

6桁コード

HMACから抽出

準備

標準ライブラリ(hmac・hashlib・struct・time・base64)だけ。

① TOTPを実装

RFC 6238 の手順そのままです。

Python
import hmac, hashlib, struct, time, base64
 
def totp(secret_base32: str, interval=30, digits=6, t=None):
    key = base64.b32decode(secret_base32.upper())
    counter = int((t or time.time()) // interval)      # 30秒枠の番号
    msg = struct.pack(">Q", counter)                   # 8バイトに
    h = hmac.new(key, msg, hashlib.sha1).digest()
    offset = h[-1] & 0x0F                               # 動的トランケーション
    code = (struct.unpack(">I", h[offset:offset+4])[0] & 0x7FFFFFFF) % (10 ** digits)
    return str(code).zfill(digits)
 
secret = "JBSWY3DPEHPK3PXP"                             # 登録時に共有する鍵
print("いまのコード:", totp(secret))

30秒待って実行すると、コードが変わります。アプリの表示とまったく同じ計算です。

② サーバー側の検証

ユーザーが入力したコードが正しいか照合します。時計のズレを考慮して前後の枠も許容するのが実務のコツ。

Python
def verify(secret, code, window=1):
    now = time.time()
    for drift in range(-window, window + 1):
        if hmac.compare_digest(totp(secret, t=now + drift * 30), code):
            return True
    return False
 
code = totp(secret)
print("検証:", verify(secret, code))       # True
print("誤りコード:", verify(secret, "000000"))

正しいコードだけTrue。window=1 で前後30秒のズレを許すので、端末の時計が多少ずれていても通ります。

🌱

QRコードの正体

アプリ登録時のQRコードは、otpauth://totp/...?secret=JBSWY3DPEHPK3PXP という文字列です。中身はこの秘密鍵。だから鍵さえ共有できれば、QRなしでも登録できます。

⚠️

秘密鍵の扱いが命

TOTPの安全性は秘密鍵の秘匿にかかっています。サーバー側では暗号化して保存し、漏洩したら即再発行を。TOTPはパスワードと組み合わせて初めて意味がある「2つ目の要素」です。

まとめ

  • TOTPは「共有秘密鍵 × 30秒枠の時刻」をHMACにかけて6桁を作る
  • サーバーとアプリが同じ計算をするので、通信なしで一致する
  • 検証は時計ズレを考慮して前後の枠も許容する
  • 秘密鍵の秘匿が命。パスワードと組み合わせる2つ目の要素
📚 もう少し詳しく(背景と理論)気になる人向け・タップで開く

TOTP(時刻ベースのワンタイムパスワード)は RFC 6238 で標準化され、その土台は RFC 4226 の HOTP(カウンタベース)です1。共有した秘密鍵と「現在時刻を30秒単位で割った値」を HMAC にかけ、そこから6桁の数字を切り出します。

サーバーとアプリが同じ鍵と時刻を持つため、通信なしで同じコードを再現できるのがしくみの核です2。時計のズレに備えて前後1ステップ(±30秒)を許容するのが一般的。フィッシングには弱い(コードを盗んで即使われる)ため、より強い耐フィッシング認証として公開鍵ベースの FIDO2/WebAuthn が普及しつつあります3。

次の一歩 🌸

多要素認証の全体像はMFA、パスワード不要のパスキー、鍵の暗号化保存はAES実装へどうぞ。

Footnotes

  1. RFC 6238 "TOTP: Time-Based One-Time Password Algorithm." HOTP(RFC 4226)のカウンタを時刻(Unix時間÷30秒)に置き換えたもの。 ↩

  2. サーバーとアプリは同じ秘密鍵と時刻から独立に同じコードを生成する。時計ズレに備え検証は前後数ステップを許容する。 ↩

  3. TOTP コードはフィッシングで盗まれ得る。FIDO2/WebAuthn は公開鍵と発信元検証により、フィッシング耐性を持つ次世代認証。 ↩

この記事をシェア:𝕏 で共有LINEで送る

🔥 この分野の最新トレンドをチェック →

あわせて読みたい