#多要素認証の方式について
AWSやGoogleの多要素認証(MFA)に使われるTOTPについて書く。
昨今普及してきたワンタイムトークン(OTP)。これはちゃんと規格化されていて、ライブラリもあるので生成は難しくない。OTPにはシークレットとカウンタ値から発行するHOTPと、シークレットと時間から計算するTOTPがある。たいていはTOTPで、HOTPはあまり見たことがないが、たぶんサーバー側と時計を合わせるのが難しいようなものの場合に使うのだろう(昔は多かったかもしれない)。ちなみにTOTPは内部的にはLinuxエポックからの経過秒数/発行間隔(30秒とか)の数値をカウント値としてHOTPに投げるものだ。
#つかってみる
是非はさておいて、AWSやGoogleの多要素認証のシークレットを取得すれば、それらの多要素認証のトークンを自分で発行することができる。AWSの場合はQRコードの下に折りたたみで隠して書いてある。Googleの方は確認してない。QRコードの場合はZXingなんかを使うと簡単にスクリーンショットからシークレットを取得することができる。
RubyならROTP、Pythonならpyotp、Node.jsではnotpというのがあるがだいたい似たようなものである。一点だけ気をつけるべきなのはBase32エンコードについてで、AWSやGoogleから供給されるものはBase32エンコードされている。ただ必ずそうなっているわけでもないらしくライブラリごとにbase32エンコードのまま受け入れるものや、エンコードとか考慮しないものとか、エンコードをオプションで指定するものなどがある。あと、nodeではthirty-twoっていうbase32のライブラリの0.0.1を使ってるものがいくつかあったけど、それはシークレットによっては正しく復号化できないで利用できない。ここにはまって数時間無駄にした。
0.0.2だと問題なくなっているので、以下のNode.jsのサンプルは0.0.2を利用する前提である。
#サンプル
var qr = require('node-zxing')();
var notp = require('notp');
var base32 = require('thirty-two');
qr.decode("qr.png",function(err,out){
var key = base32.decode(out.split(/=/)[1]);
var token = notp.totp.gen(key);
console.log(token);
});
スクリーンショットのQRコードからシークレットを取り出してトークンにすると上記のような感じになる。
ちなみにnode-zxingというのはZXingのnodeでのラッパーだけど、クラスパスの指定がコロンでハードコードされているのでWindowsでは動作しない。一応Pull requestを投げてみたけど、私の英語力とプロジェクトの放置されっぷりとかを見ると多分マージされないと思う。入れたあとに自分でWindowsならセミコロンにしたりすれば動く。一応私のフォークは以下である。
sashimizakana/node-zxing at windows-classpath-fix
#というわけで
次回はやる気があれば、これをRaspberry Piに入れて7セグに出力するMFAデバイスを手作りする。
(まとまったネタになれば自分のサイトの方に載せます)