[解決済み] PythonによるGoogle Authenticatorの実装
質問
ワンタイムパスワードを使用しようとしています。 Google Authenticatorアプリケーション .
Google Authenticatorが行うこと
基本的に、Google Authenticatorは2種類のパスワードを実装しています。
- ホットプ - HMACベースのワンタイムパスワードで、呼び出しごとにパスワードが変更されることを意味し、準拠するのは RFC4226 に準拠しています。
- TOTP - 時間ベースのワンタイムパスワードで、30秒周期で変化する(私の知る限り)。
Google Authenticatorはオープンソースとしてこちらでも公開されています。 code.google.com/p/google-authenticator
現在のコード
私は HOTP および TOTP パスワードを生成するための既存のソリューションを探しましたが、あまり見つかりませんでした。私が持っているコードは、HOTP を生成する責任を負う次のスニペットです。
import hmac, base64, struct, hashlib, time
def get_token(secret, digest_mode=hashlib.sha1, intervals_no=None):
if intervals_no == None:
intervals_no = int(time.time()) // 30
key = base64.b32decode(secret)
msg = struct.pack(">Q", intervals_no)
h = hmac.new(key, msg, digest_mode).digest()
o = ord(h[19]) & 15
h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
return h
問題は、上記のコードを使用して生成したパスワードが、Android 用の Google Authenticator アプリで生成したものと同じではないことです。複数の
intervals_no
の値を複数回試したにもかかわらず (ちょうど最初の 10000 回、最初は
intervals_no = 0
で始まる)、そして
secret
はGAアプリ内で提供されるキーと同じです。
私が持っている質問
私の質問は
- 私は何を間違えているのでしょうか?
- PythonでHOTPやTOTPを生成するにはどうしたらよいですか?
- このための既存の Python ライブラリはありますか?
要約すると、私のPythonコード内にGoogle Authenticator認証を実装するのに役立つ手がかりをください。
どのように解決するのですか?
私は私の質問に報奨金を設定したかったのですが、私は解決策を作成することに成功しました。私の問題は、不正な値に関連付けられているようだ
secret
キーの値が正しくないことです(それは
base64.b32decode()
関数の正しいパラメータでなければなりません)。
以下では、その使用方法に関する説明とともに、完全な作業ソリューションを掲載します。
コード
以下のコードで十分です。という別のモジュールとしてGitHubにアップロードしています。 onetimepass (というモジュールとしてGitHubにアップロードしました(ここから入手できます。 https://github.com/tadeck/onetimepass ).
import hmac, base64, struct, hashlib, time
def get_hotp_token(secret, intervals_no):
key = base64.b32decode(secret, True)
msg = struct.pack(">Q", intervals_no)
h = hmac.new(key, msg, hashlib.sha1).digest()
o = ord(h[19]) & 15
h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
return h
def get_totp_token(secret):
return get_hotp_token(secret, intervals_no=int(time.time())//30)
2つの機能を持つ。
-
get_hotp_token()
はワンタイムトークンを生成します(一回使用したら無効になるはずです)。 -
get_totp_token()
時間ベースのトークンを生成する(30秒間隔で変更)。
パラメータ
パラメータに至っては
-
secret
は、サーバー(上記のスクリプト)とクライアント(Google Authenticator、アプリケーション内でパスワードとして提供することによって)が知っている秘密の値です。 -
intervals_no
はトークンを生成するたびに増加する数です (これはおそらく、過去にチェックされた最後の成功の後に有限個の整数をチェックすることで、サーバー上で解決されるはずです)。
使用方法
-
生成する
secret
(の正しいパラメータである必要があります。base64.b32decode()
) - できれば16文字で (ただし=
記号は使用しないでください)、スクリプトとGoogle Authenticatorの両方で確実に動作しました。 -
使用方法
get_hotp_token()
を使用することで、ワンタイムパスワードを使用後に無効にすることができます。Google Authenticator では、このタイプのパスワードはカウンタに基づくとされています。サーバ側でこれを確認するには、いくつかのintervals_no
の値をいくつかチェックする必要があります (何らかの理由でユーザがリクエストの間にパスワードを生成していないことを保証できないため)。intervals_no
の値より小さくはありません (したがって、おそらくどこかに保存する必要があります)。 -
使用する
get_totp_token()
を使います。両方のシステムが正しい時刻を設定していることを確認する必要があります (つまり、両方のシステムが任意の時点で同じ Unix タイムスタンプを生成することを意味します)。 - ブルートフォース攻撃から身を守ることを確認します。時間ベースのパスワードが使用される場合、30 秒以内に 1000000 個の値を試すと、100% の確率でパスワードを推測することができます。HMACベースのパスワード(HOTP)の場合、さらに悪いようです。
テスト例
以下のコードをHMACベースのワンタイムパスワードに使用する場合。
secret = 'MZXW633PN5XW6MZX'
for i in xrange(1, 10):
print i, get_hotp_token(secret, intervals_no=i)
を実行すると、次のような結果になります。
1 448400
2 656122
3 457125
4 35022
5 401553
6 581333
7 16329
8 529359
9 171710
は、Google Authenticatorアプリが生成するトークンに対応します(ただし、6文字より短い場合は、アプリが先頭にゼロを追加して6文字にします)。
関連
-
[解決済み] なぜGoogleはJSONレスポンスにwhile(1);を前置するのでしょうか?
-
[解決済み] Pythonには文字列の'contains'サブストリングメソッドがありますか?
-
[解決済み] Pythonで現在時刻を取得する方法
-
[解決済み] Pythonで2つのリストを連結する方法は?
-
[解決済み] ファイルのコピー方法について教えてください。
-
[解決済み] Pythonで例外を手動で発生(スロー)させる
-
[解決済み】ネストされたディレクトリを安全に作成するには?
-
[解決済み】Pythonに三項条件演算子はありますか?
-
[解決済み] PythonからSMTPを使用してメールを送信する
-
[解決済み] matplotlib でプロットの軸、目盛、ラベルの色を変更する方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Google Authenticatorが公共サービスとして利用可能に?
-
[解決済み] SQLAlchemy: セッションの作成と再利用
-
[解決済み] なぜ(0-6)は-6=偽なのか?重複
-
[解決済み] PythonからSMTPを使用してメールを送信する
-
[解決済み] Pythonで0xを使わずにhex()を使うには?
-
[解決済み] Flask でグローバル変数はスレッドセーフか?リクエスト間でデータを共有するには?
-
[解決済み] Pandasを使って、既存のExcelファイルに新しいシートを保存する方法は?
-
[解決済み] Pythonで、ウェブサイトが404か200かを確認するためにurllibをどのように使用しますか?
-
[解決済み] Python の sorted() はどのようなアルゴリズムを使っているのですか?重複
-
[解決済み] pipの依存性/必要条件をリストアップする方法はありますか?