ASP.NETでGoogle Authenticatorを用いたニ段階認証を行う(その2)

前回はニ段階認証でログインできるとこまで確認しました。
tech.sanwasystem.com

セキュリティポリシーによりますが、サイトによってはニ段階認証を一度成功した場合、一定期間はニ段階認証なしにログインを許容するといったケースがあります。
弊社が利用しているサービスではニ段階認証に以下のような差異があります。

service 説明
Google Apps 登録時一回認証。一度認証すれば三十日間は再認証不要。ID/パスワードでのログイン成功後に段階認証の入力が求められる。
Slack 登録時二回認証。登録時に二段階認証アプリを登録したデバイス紛失時のためのコードが表示される。 (下記図参照)
AWS 登録時二回認証。ログインの再は必ずニ段階認証を求められる。ID/パスワード/ニ段階認証コードを1画面で入力する。

f:id:ihisa:20150715093139p:plain

というわけでGoogle Appsライクにこれを実装します。

1.ニ段階認証成功時、cookieに改ざんできない&推測できない様暗号化した文字列をセットしておく

HttpCookie cookie = new HttpCookie(
    "Cookie名", 
    this.GetHash("ユーザーにシステム内部で紐づくキー"));

cookie.Expires = DateTime.Now.AddDays(30);

Response.Cookies.Add(cookie);

2.ID/passwordの組み合わせでの認証成功後、cookie内にセットしておいた文字列で認証し、成功時はニ段階認証を飛ばす

HttpCookie cookie = Request.Cookies["Cookie名"].ToString()];

// 認証
if (((cookie != null)) && (cookie.Value == this.GetHash("ユーザーにシステム内部で紐づくキー")))
{
    // 認証OK
}
private string GetHash(string hashkey)
{
    byte[] HashKeyFrom = Encoding.UTF8.GetBytes(hashkey);

    byte[] HashKeyTo;
    using (SHA256CryptoServiceProvider provider = new SHA256CryptoServiceProvider())
    {
        HashKeyTo = provider.ComputeHash(HashKeyFrom);
    }

    StringBuilder StringHashKey = new StringBuilder();
    for (int i = 0; i < HashKeyTo.Length; i++)
    {
        StringHashKey.AppendFormat("{0:X2}", HashKeyTo[i]);
    }

    return StringHashKey.ToString();
}

cookieの中身をchromeで見るとこんな感じになります。
f:id:ihisa:20150717101709p:plain

cookieの有効期間はHttpCookie.Expiresに設定されないので有効期間を経過しているかどうかはHttpCookieがnullかどうかで判断します。しっかり実装する際は有効期限はcookieに委ねずシステム側で管理する様にしましょう。