Google Authenticatorアプリケーションを用いて時間ベースのワンタイムパスワード(TOTP:Time-based One Time Password)を用いてニ段階認証します。
この認証方式ですが、名称がバラバラみたいです。AWSではMulti-Factor Authentication、Google Appsでは2-Step Verification、SlackではTwo factor authentication。意味合いはどれも一緒ですが。
で、今回使うGoogle Authenticatorはこちら。これでニ段階認証します。
Androidhttps://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=ja
環境
ASP.NET Web Forms
.NET Framework 4
必要なパッケージのインストール
OTP Sharp
OTP Sharpの依存関係であるBase32
Qr Code library
QRコードはオンラインでもできますが今回はローカルで作成します。
https://google-developers.appspot.com/chart/infographics/docs/overview
1. ニ段階認証アプリケーション登録のための処理
やることはこれだけです。画像は直接Data URI schemeで描画します。
- 認証に用いる一意なキー(認証キー)を発行
- ニ段階認証登録用URLを作成
- 作成したURLを元にQRコード画像作成
using Base32; using MessagingToolkit.QRCode.Codec; using OtpSharp; using System; using System.Drawing; using System.IO; // 認証キーの作成とQRコードに埋め込むURL作成 byte[] secretKey = KeyGeneration.GenerateRandomKey(20); string userName = "username"; string qrcodeUrl = KeyUrl.GetTotpUrl(secretKey, userName) + "&issuer=HogeHogeApplication"; // QRコードが読めなかった場合のキーコード表示 this.QRCodeKey.Text = Base32Encoder.Encode(secretKey); // QRコード画像作成 QRCodeEncoder enc = new QRCodeEncoder(); enc.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE; enc.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M; Image qrimage = enc.Encode(qrcodeUrl); // 画像をBase64に変換 string qrcodestring = string.Empty; using (var ms = new MemoryStream()) { qrimage.Save(ms, System.Drawing.Imaging.ImageFormat.Png); qrcodestring = Convert.ToBase64String(ms.GetBuffer()); } // Data URI schemeで描写 this.QRImage.ImageUrl = String.Format("data:{0};base64,{1}", "image/png", qrcodestring);
QRコード <asp:Image ID="QRImage" runat="server" /> <asp:Label ID="QRCodeKey" runat="server"></asp:Label> 認証キー入力 <asp:TextBox ID="DigitCode" runat="server"></asp:TextBox> <asp:Button ID="Register" runat="server" Text="登録" OnClick="Register_Click" />
2. Google Authenticatorのインストールとキーの追加
- 画面に表示されたQRコードをGoogle Authenticatorでスキャン(QRコードが読めない場合用に1-1で作成した認証キーを画面表示しておき、手入力可能にしておく)
- Google Authenticatorに表示されるワンタイムパスワードで認証させる(後述するログイン処理と同等の処理を行う)
- 認証成功時に認証キーを該当ユーザに紐づける(テーブル等に保存しておく)
3. いざ二段階認証でログイン
- 入力されたワンタイムパスワード値を比較
using Base32; using OtpSharp; // qrcodestringは1-1で作成した認証キー文字列 byte[] secretKey = Base32Encoder.Decode(qrcodestring); long timeStepMatched = 0; Totp totp = new Totp(secretKey); // 入力されたワンタイムパスワードで認証 if (totp.VerifyTotp(this.DigitCode.Text, out timeStepMatched, new VerificationWindow(1, 1))) { // ニ段階認証成功! } else { // ニ段階認証失敗! }
VerifyTotpの第3引数のVerificationWindowは許容するワンタイムパスワードのずれ幅です。
https://bitbucket.org/devinmartin/otp-sharp/wiki/TOTP
お手軽に実装できました。