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

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

2026-09-13実践

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

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

しくみ:秘密鍵 × 時刻

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

鍵と時刻から6桁

🔑

共有の秘密鍵

登録時に配布

⏱️

30秒枠の時刻

両者で一致

🔢

6桁コード

HMACから抽出

準備

標準ライブラリ(hmachashlibstructtimebase64)だけ。

① TOTPを実装

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

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秒待って実行すると、コードが変わります。アプリの表示とまったく同じ計算です。

② サーバー側の検証

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

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"))

正しいコードだけTruewindow=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 は公開鍵と発信元検証により、フィッシング耐性を持つ次世代認証。

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

あわせて読みたい