Windows Hello を使った App 開発


Windows Hello を使った開発

こんにちは。

いよいよ、Windows 10 がダウンロード開始されました。
今週は「Windows 10 らしいアプリケーション開発」の例として、Windows 10 からの新しい API を使って、Windows Hello と連携したアプリ開発をおこなってみましょう。

補足 (2016/03/31 追記) : Microsoft Edge (ブラウザー) を使った JavaScript アプリケーションにおいても、API (JS の API) を使った Windows Hello との連携開発が可能になりました。詳細は、下記を参照してください。
https://channel9.msdn.com/Events/Build/2016/P514

 

Windows Hello と連携した UWP App

よりセキュアに、でも入力は簡単に、という取り組みは、これまで多くの欧米系の IT ベンダーが挑戦してきました。
以前、「Windows 10 との SSO 開発」でも紹介したように、Windows 10 では、こうした取り組みの成果の 1 つとして、Microsoft Passport (旧 Next Generation Credential) という先進的な認証フレームワークが使用されています。(Microsoft Passport は、FIDO 2.0 の実装になっています。)

これまで、人が理解できる軽微な文字列をネットワーク上に流すパスワードを使った方式を使用していましたが (もちろん、これまでも SSL 暗号化など必要な対策は行われていました)、Windows 10 では、private key を Windows 10 の device 側に、public key を server 側 (オンプレミスの Active Directory, Azure AD など) に登録して信頼関係を確立します。
ネットワーク上を流れない PIN や biometric 認証機能の「Windows Hello」を使って TPM (つまり、ソフトウェア的に可搬ではなく、ハードウェアに依存した入れ物) に登録された private key を取り出し、この private key を使って必要な data (server から渡された challenge など) にデジタル署名 (sign) をおこなって server 側に渡し、server 側では public key を使ってこの署名が正しいことを検証 (verify) して、問題なければ処理を継続します。例えば、Azure AD Join では、ロック スクリーンからの回復の際など、都度、refresh token をこのような方法で (署名を添付して) 受け渡しています。
この基本的な流れ (Flow) は、この後の App 開発でもそのまま応用しますので、プログラマーの方は是非理解しておいてください。

この方式では、ソフトウェア的な PIN とハードウェア的な Device、あるいは、生体情報と Device などの複数の認証要素の組み合わせ (ソフト的なものとハード的なものの組み合わせ) になっており、かつ、前者はネットワーク上を流れないため Attack の危険などがありません。しかも、従来の方式 (Kerberos, OAuth 2.0 など) をすべて塗り替えるまったく新しい方式ではなく、これら既存技術の拡張として実装されています (従来技術との親和性も考慮されています)。
また、こうした先進的な (セキュアな) 取り組みでは、それに伴い利用者の手間が増えるのが一般的ですが、「Windows Hello」(biometrics 認証, 生体認証) を組み合わせることで、むしろ入力の手間を簡素化しながらセキュリティを強化している点に注目してください。生体情報の登録は端末ごとに個別におこないますが、元となる情報は唯一無二のものであり、生体情報を使えば、端末ごとに個別の PIN コードを持ち歩くような手間もありません。Windows 10 のイメージ ビデオでも紹介されているように、小さな子供でも、この高度なセキュリティ機構を意識せずに扱えます。
Windows 10 では、単に、従来の指紋認証に顔認証などが加わったということではなく、上記のように、むしろ従来のパスワードを使った認証方法よりも、この新しい認証方法のほうが推奨されます。

そして、著名な「Making Windows 10 More Personal With Windows Hello」のビデオの 30 秒あたりを見てください。Microsoft Dynamics のアプリにアクセスする際、アプリ (Microsoft Dynamics) が独自に Windows Hello による biometrics 認証を起動しています。

このビデオが示しているように、皆さんが構築するアプリケーションにも、上述の Microsoft Passport と Windows Hello による付加価値を実装できるようになっています。

なお、Windows Hello では、Fingerprint (指紋認証), Face (顔認証), Iris (虹彩認証) の 3 種類の biometrics 認証が使用可能ですが、今回のサンプルでは Fingerprint のみを使用します。(顔認証をおこなうには深度を理解できるカメラが必要ですが、残念ながら、私の環境には入っていないためです。Fingerprint だけなら Windows 8.1 の頃からも可能でしたが、ここで使用する API や方式は Windows 10 による新しい仕組みです。。。)

 

API の概要

上述の通り、Windows 10 では、Device 側 (PC など) でキーペア (private key / public key) を発行して private key を管理し、Server 側 (ISV の皆さんが提供するサービスなど) で public key を含む管理や確認処理を委ねます。ここで紹介する API (KeyCredentialManager オブジェクト) は、Windows Hello と連携して、このうちの前者 (Device 側) を担当します。

用途として、今回紹介するキーペアを使った仕組みを Application の認証 (ログイン) に使うこともできます。ただし、この方式は、「確実にその Device で、その User が使っている」ことを保証しますが、例えば、「その Service を使って良い User である」といったことは保証しないので、こうした部分は追加の仕組みと組み合わせる必要があります。
また別の用途として、既にログイン済の Application に追加の認証をおこなう目的で使用しても構いません。この API は Device と Biometrics の情報に関連付いているため、User / Password 方式などでログイン済の Application でも、非常にセキュアな処理が必要とされる場面で Windows Hello の認証を要求して、「確実にその利用者が操作していること」を保証することができるためです。(例えば、EC サイトにおける購入処理などのセキュアな処理に入る前に再確認したり、院内システムのように人命や機微な個人情報に関わるシステムで特定の操作の前に再確認したり、など)

また、この API は、Office 365 とのシングル・サインオンなど、既存のプロバイダーやサービス (Azure AD, Microsoft Account など) との連携を担当するものではありません。上述の通り、この API は、Server 側ではなく、Device 側の処理を担当します。Server 側との連携は、開発者の皆さん自身が構築する想定です。既存の Azure AD 連携も含めた処理を API から操作するには、ここで紹介する API (KeyCredentialManager) ではなく「Windows 10 との SSO 開発 (Web Account Manager を使用したNative Application)」で解説した Web Account Manager API などを使用します。

 

環境準備

まず、下記の通り、開発環境を準備します。

  • 開発環境として使用する Windows 10 のマシンで、[開発者向けモード] をあらかじめオンにします。
  • Visual Studio 2015 のインストールの際に、Universal Windows App の開発ツールを忘れずにインストールします。

また、使用するアカウントで、[設定] 画面を開いて、[サインイン オプション] で Windows Hello (顔認証、指紋認証など) を有効にします。(この際、生体情報を Windows に設定します。)

また、こちら で記載しているように、後述する KeyCredentialManager を使用するためには Microsoft Account で接続する必要があるため、ローカル アカウント (Local Account) を使用している場合は、下図のとおり Microsoft Account を使用したサインインに切り替えておいてください。(オンプレミスの Active Directory を使って Domain Join しているユーザーの場合は不要です。)
なお、Azure AD Join で組織または学校のアカウント (Organization or School Account) を使用した場合は、残念ながら KeyCredentialManager が使用できないようなので注意してください。

 

プログラミング

上述の通り、Windows 10 自身が private key と public key を使用して信頼関係を設定していますが、Microsoft Passport を使って、皆さんのアプリケーションでも、こうした処理をプログラミングできます。
このあと紹介するサンプルでは、private key と public key の作成の際に、取得した public key の key size を表示し、private key を使った sign (デジタル署名の作成) の際に、デジタル署名の Base64 エンコード文字列を表示する単純なサンプルを構築しますが、以前「Azure AD : Service 開発」でも紹介したように、private key と public key の準備ができれば、さまざまな言語で署名 (sign) と検証 (verify) が可能ですので、アプリ内認証だけでなく、アプリとサーバー間の信頼関係の確立など、さまざまな形で利用が可能です。

まず、Visual Studio 2015 を起動して UWP (Universal Windows Platform) App のプロジェクトを新規作成します。

MailPage.xaml に、下図のとおり、SignIn のボタンを配置しましょう。
このボタンを押した際に、Windows Hello を呼び出して認証をおこないます。

SignIn ボタンを押した際の処理として、今回、下記のコードを記載します。

下記では、はじめて この App を使用する際に Key Credential の作成 (RequestCreateAsync) をおこないます。内部では、private key と public key が作成され、private key は TPM に登録され、PIN や Windows Hello (指紋認証、顔認証など) によって保護されます。(このため、この際、PIN の入力や biometrics 認証が求められます。)

2 回目以降、この App に SignIn する際には、PIN の入力や biometrics 認証を使って、この登録された private key を使ったデジタル署名 (RequestSignAsync) が可能です。
下記のコメントで記載した通り、Sign (デジタル署名) された data は public key を使って Verify が可能なので (UWP App の場合、CryptographicEngine.VerifySignature() を使用します)、アプリケーションでさまざまな形で信頼関係を確立するためのプログラミングが可能です。(上述の通り、今回は単純に、public key の key size の表示と、デジタル署名の Base64 エンコード文字列の表示のみをおこなっています。)

. . .
using Windows.UI.Popups;
using Windows.Security.Credentials;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
. . .

private async void signinButton_Click(object sender, RoutedEventArgs e)
{
  // check if KeyCredentialManager can be used
  if (await KeyCredentialManager.IsSupportedAsync() == false)
  {
    await (new MessageDialog("KeyCredentialManager not supported")).ShowAsync();
    return;
  }

  // retrieve private key for sign
  KeyCredentialRetrievalResult res =
    await KeyCredentialManager.OpenAsync("key1");

  if (res.Status == KeyCredentialStatus.Success)
  {
    //
    // If it is present, we request sign for some data
    //

    // convert string to binary buffer
    var inputbuf =
      CryptographicBuffer.ConvertStringToBinary(
        "Test Data 1", BinaryStringEncoding.Utf8);

    // sign using retrieved private key
    // (Windows Hello is diplayed here !)
    KeyCredentialOperationResult signRes =
      await res.Credential.RequestSignAsync(inputbuf);

    // get the base64 encoded data to cryptographically sign
    string base64encSignature =
      CryptographicBuffer.EncodeToBase64String(signRes.Result);
    await (new MessageDialog(base64encSignature)).ShowAsync();
  }
  else if (res.Status == KeyCredentialStatus.NotFound)
  {
    //
    // If the credential is not found, we create it.
    //

    // Create the credential
    // (Windows Hello is diplayed here !)
    KeyCredentialRetrievalResult createRes =
      await KeyCredentialManager.RequestCreateAsync("key1",
      KeyCredentialCreationOption.ReplaceExisting);

    // if the status is success, retrieve the public key.
    if (createRes.Status == KeyCredentialStatus.Success)
    {
      var pubKey = createRes.Credential.RetrievePublicKey();
      AsymmetricKeyAlgorithmProvider alg =
        AsymmetricKeyAlgorithmProvider.OpenAlgorithm(
          AsymmetricAlgorithmNames.RsaSignPkcs1Sha256);
      CryptographicKey ckey = alg.ImportPublicKey(pubKey);
      // for verification, CryptographicEngine.VerifySignature() with this CryptographicKey
      // This time, just showing the keysize . . .
      var dialog = new MessageDialog(string.Format("Key size is {0}", ckey.KeySize));
      await dialog.ShowAsync();
    }
  }
  else
  {
    await (new MessageDialog("Unknown error !")).ShowAsync();
  }

}
. . .

Credential の作成 (RequestCreateAsync) やデジタル署名の作成 (RequestSignAsync) の際には、下図のとおり、App により、PIN や biometrics の入力が促されます。
わざわざ文字列を入力しなくても、Windows Hello により、指をこすりつけたり、顔を近づけるだけで先に進むことができます。

また、上記で使用する KeyCredential の名前 (上記コードの key1) は、Account ごとに一意に認識されるので注意してください。例えば、User1 が key1 を登録した場合、User2 で Login して key1 を参照しても、NotFound になります。(User2 は個別に key1 を作成できます。)

登録された KeyCredential は、下記の通り削除できます。

private async void DeleteButton_Click(object sender, RoutedEventArgs e)
{
  await KeyCredentialManager.DeleteAsync("key1");
}

 

App ごとの Isolation

Key は User、Application で分離 (Isolate) されているので注意してください。例えば、上記の key1 は、別の Application からアクセスしても異なる Key として認識されます。(Application1 から登録した key1 の値を Application2 から取得できません。) また、同じ Application であっても、もちろん User が異なれば、やはり別の Key として扱われます。

このため、既存の Azure AD (Office 365) で使用している Key をこの方法で取得できないので注意してください。ここで紹介している方法は、あくまで皆さんが提供する Application と Service で使用するものです。(既存の Azure AD (Office 365) の Key を UWP アプリで扱う場合は、「Windows 10 との SSO 開発 (Web Account Manager を使用したNative Application)」 で解説している Web Account Manager API などを使用します。)
(2016/05 追記)

 

==========

補足

単に、ある特定の箇所で biometrics 認証を呼び出して OK か否か確認したい場合には、既に Windows 8.1 (ストア アプリ) の頃から使用可能な UserConsentVerifier があり、UserConsentVerifier.RequestVerificationAsync によって下図のように Fingerprint (指紋認証) を表示します。(下図は Windows 8.1 で動作させた場合の実行結果です。)

. . .
using Windows.Security.Credentials.UI;
. . .

private async void importantButton_Click(object sender, RoutedEventArgs e)
{
  if (await UserConsentVerifier.CheckAvailabilityAsync() ==
    UserConsentVerifierAvailability.Available)
  {
    UserConsentVerificationResult res =
      await UserConsentVerifier.RequestVerificationAsync(
        “This is sensitive operation ! Please authenticate again.”);
    if(res == UserConsentVerificationResult.Verified)
    {
      // some important action …
    }
  }
}
. . .

しかし、Windows 10 の UWP App で UserConsentVerify を使用すると、下図の通り Fingerprint は表示されないので注意してください。
Windows 10 の UWP App では、上述の新しい API を使って、Sign と Verify とモデルで構築してください。

==========

 

今回は、新しい API を C# (.NET) を使って使用しましたが、UWP 用の Native API も提供されていて、本年 (2015 年) 末までには JavaScript API も提供予定とのことです。(BUILD のセッション 2-639「Microsoft Passport and Windows Hello: Moving Beyond Passwords and Credential Theft」を参照してください。)

Comments (0)

Skip to main content