June 2019
Volume 34 Number 6
[ASP.NET Core 3.0]
ASP.NET Core での AI 搭載の生体認証セキュリティ
2 部から成るこの記事では、ASP.NET Core 3 のポリシーベースの認可モデルを紹介します。これは、基になるユーザー ロールから認可ロジックを切り離すことを目的としています。次に、顔認識や音声認識などの生体認証情報に基づく、この認可プロセスの具体的な例を提示します。このケースでは、不正侵入が検出されると建物への入場が制限されます。侵入の重大度は、Azure Machine Learning に組み込まれた異常検出サービスによって評価されます。
会場への入場
コンテキストは厳重なセキュリティ対策が施された会場です。軍事区域、病院、データセンターをご想像ください。いくつかの制限により、入場は許可されている人に限られます。次の手順は、それぞれの建物のドアで入館手続きを行うために施行されるセキュリティ フローを示しています。
- 入場を要求する人物がドアのカード リーダーにアクセス パスを通します。
- カメラが動きを検出して人物の顔と体をキャプチャします。これにより、印刷された写真などを使用して、顔のみの認識でカメラをだますことを防ぎます。
- カード リーダーとカメラはモノのインターネット (IoT) デバイスとして登録されており、記録されたデータを Azure IoT Hub にストリーム配信します。
- Microsoft Cognitive Services がその人物を、入場が許可された人物のデータベースと照合します。
- 認可フローにより、IoT デバイスで収集された生体認証情報が、アクセス パス上のその人物の ID と照合されます。
- Azure 機械学習サービスが呼び出され、入場要求のリスク レベルと、それが不正侵入かどうかを評価します。
- 前の手順で定義されたプロファイルによって所有されている特定のポリシー要件を確認して、ASP.NET Core Web API によって認可が付与されます。
検出された人物の ID とアクセス パスが一致しない場合、会場への入場は即座にブロックされます。そうでない場合はフローが継続し、次の異常のいずれかが発生していないかどうかがチェックされます。
- 建物への異常な入場頻度。
- その人物が前に退館 (チェックアウト) しているかどうか。
- 1 日に許可される入場回数。
- その人物が勤務時間中かどうか。
- 建物の重要度 (社員食堂なら入場の制限は必要なくても、サーバー データセンターへの入場にはより厳密なポリシーを適用します)。
- その人物に同伴者や手荷物があるかどうか。
- 過去に同じ建物への同様の類型的な入場があったかどうか。
- 過去に測定されたリスク レベルの変化。
- 過去に検出された侵入の回数。
Azure Machine Learning で異常検出サービスが実行されて、スコアを返します。これは、この入場が標準から逸脱しているかどうかの可能性として表されます。スコアは 0 - 1 の範囲で表されます。0 は「リスク未検出」で、まったく問題なく、完全な信頼が付与されます。1 は「非常警報」で、即座に入場がブロックされます。各建物のリスク レベルに応じて、値が 0 より大きい場合に建物への入場を許可できると見なされるしきい値が決定されます。
ASP.NET Core での認可
ASP.NET Core には、単純な認可宣言型ロールと豊富なポリシー ベースのモデルが提供されています。認可は要件で表現され、ユーザーの要求はそれらの要件に照らしてハンドラーによって評価されます。会場へのユーザーの入場を認可するために、カスタム ポリシー要件とそれらの認可ハンドラーを生成する方法について説明します。ASP.NET Core の認可モデルの詳細については、bit.ly/2UYZaJh でドキュメントを参照してください。
前述のように、カスタム ポリシー ベースの認可メカニズムは、要件と (通常は) 認可ハンドラーで構成されます。建物への入場許可は、入り口のドアをロック解除する API の呼び出しで構成されます。IoT デバイスによって生体認証情報が Azure IoT Hub にストリーム配信されます。すると、会場の一意識別子である会場 ID がポストされ、検証ワークフローがトリガーされます。認可が成功した場合、Web API POST メソッドは、単に HTTP コード 200 と、ユーザー名と会場 ID を含む JSON メッセージを返すだけです。そうでない場合は、予期されるとおり、HTTP 401 不正アクセス エラー コードがスローされます。それでは、順を追って見ていきましょう。Web API の Startup クラス、具体的には、ConfigureServices メソッドから始めます。これには、ASP.NET Core アプリケーションを実行するために必要なサービスの構成手順が含まれています。サービス オブジェクト上で AddAuthorization メソッドを呼び出して、認可ポリシーが追加されます。AddAuthorization メソッドはポリシーのコレクションを受け取ります。API 関数は、呼び出されたときに実行の認可を得るために、これらを所有する必要があります。このケースで必要なポリシーは 1 つだけです。これに "AuthorizedUser" という名前を付けました。 ただし、このポリシーは、確認する人物の生体的特徴 (顔、体、声) を反映した、満たすべき複数の要件があります。この 3 つの要件は、それぞれ、図 1 に示すように、IAuthorizationRequirement インターフェイスを実装する特定のクラスによって表現されます。AuthorizedUser ポリシーの要件を一覧表示するときに、要件を満たすために必要な信頼度レベルも指定します。前述のように、0 から 1 までのこの値は、それぞれの生体的属性の識別の精度を表します。後で Cognitive Services を使用した生体認証の説明をするときにこの点に戻ります。
図 1 Web API での認可要件の構成
public void ConfigureServices(IServiceCollection services)
{
var authorizationRequirements = new List<IAuthorizationRequirement>
{
new FaceRecognitionRequirement(confidence: 0.9),
new BodyRecognitionRequirement(confidence: 0.9),
new VoiceRecognitionRequirement(confidence: 0.9)
};
services
.AddAuthorization(options =>
{
options.AddPolicy("AuthorizedUser", policy => policy.Requirements =
authorizationRequirements);
})
AuthorizedUser 認可ポリシーには複数の認可要件が含まれており、ポリシー評価を成功させるためにはすべての要件に合格する必要があります。つまり、1 つの認可ポリシーに追加された複数の認可要件が AND ベースで処理されます。
ソリューションで実装した 3 つのポリシー要件はすべて、IAuthorizationRequirement インターフェイスを実装するクラスです。このインターフェイスは実際には空です。つまり、メソッドの実装を指示しません。3 つの要件を一貫して実装するために、パブリックの ConfidenceScore プロパティを指定しました。これは、この要件に合格したと見なすために認識 API が満たすべき、想定される信頼度レベルを取得するためのものです。FaceRecognitionRequirement クラスは次のようになります。
public class FaceRecognitionRequirement : IAuthorizationRequirement
{
public double ConfidenceScore { get; }
public FaceRecognitionRequirement(double confidence) =>
ConfidenceScore = confidence;
}
同様に、体と声の認識に関するその他の要件が、それぞれ、BodyRecognitionRequirement クラスと VoiceRecognitionRequirement クラスで実装されます。
Web API アクションを実行するための認可は、Authorize 属性を通して制御されます。簡単に言うと、AuthorizeAttribute をコントローラーまたはアクションに適用すると、そのコントローラーまたはアクションへのアクセスは認証済みのユーザーに制限されます。会場への入場を制御する Web API は、Post アクションのみを含む、単一のアクセス コントローラーを公開します。このアクションは、指定された"AuthorizedUser"ポリシー内のすべての要件が満たされた場合に認可されます。
[ApiController]
public class AccessController : ControllerBase
{
[HttpPost]
[Authorize(Policy = "AuthorizedUser")]
public IActionResult Post([FromBody] string siteId)
{
var response = new
{
User = HttpContext.User.Identity.Name,
SiteId = siteId
};
return new JsonResult(response);
}
}
各要件は、図 2 のように、ポリシー要件の評価を担当する認可ハンドラーによって管理されます。すべての要件用の 1 つのハンドラーを用意することも、要件ごとに別々のハンドラーを用意することもできます。この後者のアプローチはより柔軟です。Startup クラスで簡単に構成可能な認可要件のグラデーションを構成することができるためです。顔、体、声の要件ハンドラーは、AuthorizationHandler <TRequirement> 抽象クラスを拡張します。ここで、TRequirement は処理すべき要件です。3 つの要件を評価するために、FaceRecognitionRequirement、BodyRecognitionRequirement、VoiceRecognitionRequirement のそれぞれに対して AuthorizationHandler を拡張するカスタム ハンドラーを作成する必要があります。具体的には、認可要件が満たされているかどうかを判断する HandleRequirementAsync メソッドです。このメソッドは、非同期であるため、タスクが完了したことを示す以外は、実際の値を返しません。認可の処理は、認可ハンドラーのコンテキストで Succeed メソッドを呼び出して、要件に "successful"のマークを付けることで構成されます。これは、実際には、Cognitive Services API を内部的に使用する「認識エンジン」オブジェクトによって検証されます (次のセクションで詳しく説明します)。Recognize メソッドによって実行される認識アクションは、識別された人物の名前を取得して、識別が正しい (1 に近い値) のか正しくない (0 に近い値) のかの信頼度レベルを表す値を返します。想定レベルは API のセットアップで指定してあります。この値は、ご自分のソリューションに適切なしきい値に調整できます。
図 2 カスタム認可ハンドラー
public class FaceRequirementHandler :
AuthorizationHandler<FaceRecognitionRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
FaceRecognitionRequirement requirement)
{
string siteId =
(context.Resource as HttpContext).Request.Query["siteId"];
IRecognition recognizer = new FaceRecognition();
if (recognizer.Recognize(siteId, out string name) >=
requirement.ConfidenceScore)
{
context.User.AddIdentity(new ClaimsIdentity(
new GenericIdentity(name)));
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
特定の要件を評価することに加え、認可ハンドラーは、現在のユーザーに ID 要求も追加します。ID の作成時に、信頼できる団体から発行された 1 つ以上の要求が割り当てられる場合があります。要求は、対象が何かを表す、名前と値の組です。このケースでは、文脈の中でユーザーに ID 要求を割り当てます。その後、この要求は、アクセス コントローラーの Post アクションで取得され、API の応答の一部として返されます。
このカスタム認可プロセスを有効にするために実行する最後の手順は、Web API 内のハンドラーの登録です。ハンドラーは、構成中にサービス コレクションに登録されます。
services.AddSingleton<IAuthorizationHandler, FaceRequirementHandler>();
services.AddSingleton<IAuthorizationHandler, BodyRequirementHandler>();
services.AddSingleton<IAuthorizationHandler, VoiceRequirementHandler>();
このコードは、ASP.NET Core に組み込まれた依存性注入 (DI) フレームワークを使用して、各要件ハンドラーをシングルトンとして登録します。アプリケーションの起動時にハンドラーのインスタンスが作成され、DI によって関連するオブジェクトに登録済みのクラスが挿入されます。
顔の識別
このソリューションは、Vision API が人物の顔と体を識別できるよう、Azure Cognitive Services を使用します。Cognitive Services と API の詳細については、bit.ly/2sxsqry にアクセスしてください。
Vision API は、顔属性検出と顔認証を提供します。顔検出とは、画像内にある人間の顔を検出する能力を意味します。この API は、処理された画像内の顔の位置の直交座標を返しますが、必要に応じて、頭部姿勢、性別、年齢、感情、顔ひげ、眼鏡などの顔に関連する一連の属性を抽出することができます。これに対して、顔認証は、人物の事前に保存された顔に照らして、検出された顔の認証を実行します。事実上、2 つの顔が同じ人物のものかどうかを評価します。これが、このセキュリティ プロジェクトで特に使用する API です。まず、ご自身の Visual Studio ソリューションに次の NuGet パッケージを追加してください。Microsoft.Azure.CognitiveServices.Vision.Face 2.2.0-preview
.NET マネージド パッケージはプレビューのため、図 3 に示すように、NuGet を参照するときには [プレリリースを含める] オプションがオンになっていることを確認します。
図 3 Face API 用の NuGet パッケージ
.NET パッケージを使用すれば、顔検出と認識が容易になります。大まかに言えば、顔認識は 2 つの異なる顔を比較して似ているのか、同じ人物のものなのかを判断する作業です。認識操作のほとんどで、図 4 に示すデータ構造が使用されます。
図 4 Face API 用のデータ構造
名前 | 説明 |
DetectedFace | これは、顔検出操作によって取得される単一の顔表現です。その ID は作成後 24 時間で有効期限が切れます。 |
PersistedFace | DetectedFace オブジェクトがグループ (FaceList や Person など) に追加されると、PersistedFace オブジェクトになり、いつでも取得できて、無期限で使用できるようになります。 |
FaceList/LargeFaceList | これは、種々の PersistedFace オブジェクトから成るリストです。FaceList は、一意の ID、名前文字列、オプションのユーザー データ文字列を持ちます。 |
ユーザー | これは、同じ人物に属している PersistedFace オブジェクトのリストです。一意の ID、名前文字列、オプションのユーザー データ文字列を持ちます。 |
PersonGroup/LargePersonGroup | これは、種々の Person オブジェクトから成るリストです。一意の ID、名前文字列、オプションのユーザー データ文字列を持ちます。PersonGroup は、認識操作で使用する前に、トレーニングする必要があります。 |
認証操作では、画像内で検出された顔のリスト (DetectedFace コレクション) から顔 ID が取得され、保存された顔のコレクション (PersistedFace) に照らして ID を比較し、顔が同じ人物のものかどうかが判断されます。一意の ID と名前を持つ保存された顔画像によって 1 人の人物が特定されます。必要に応じて、人物のグループを PersonGroup にまとめることで、認識パフォーマンスを上げることができます。基本的に、1 人の人物が ID の基本単位であり、Person オブジェクトには 1 つ以上の既知の顔を登録できます。各人物は特定の PersonGroup (人物のコレクション) 内で定義され、PersonGroup に照らして識別が行われます。セキュリティ システムは、1 つ以上の PersonGroup オブジェクトを作成してから、それらに人物を関連付けます。グループが作成されたら、それを使用して識別を行う前に、PersonGroup コレクションをトレーニングする必要があります。さらに、人物が追加または削除された場合や、誰かが登録された自分の顔を編集した場合には、このコレクションを再トレーニングする必要があります。トレーニングは PersonGroup Train API によって行われます。クライアント ライブラリを使用している場合は、TrainPersonGroupAsync メソッドを呼び出すだけで済みます。
await faceServiceClient.TrainPersonGroupAsync(personGroupId);
トレーニングは非同期プロセスです。そのため、TrainPersonGroupAsync メソッドから戻っても完了していない場合があります。その準備が整うまでは、GetPersonGroupTrainingStatusAsync メソッドでトレーニングの状態のクエリを実行してから、顔認識または認証に進む必要があるでしょう。
顔認証の実行中は、Face API がグループ内のすべての顔の中から検出された顔の類似度を計算し、そのテストの顔に最も該当する人物を返します。これは、クライアント ライブラリの IdentifyAsync メソッドを通して実行されます。テストの顔は前述の手順を使用して検出する必要があり、その結果、顔 ID が 2 番目の引数として Identify API に渡されます。一度に複数の顔 ID を識別することができ、結果にはすべての Identify の結果が表示されます。既定で、Identify は、テストの顔に最も一致する 1 人の人物だけを返します。必要に応じて、オプション パラメーターの maxNumOfCandidatesReturned を指定して、Identify が複数の候補を返すようにすることもできます。図 5 のコードは、顔を識別して検証するプロセスを示しています。
図 5 顔認識プロセス
public class FaceRecognition : IRecognition
{
public double Recognize(string siteId, out string name)
{
FaceClient faceClient = new FaceClient(
new ApiKeyServiceClientCredentials("<Subscription Key>"))
{
Endpoint = "<API Endpoint>"
};
ReadImageStream(siteId, out Stream imageStream);
// Detect faces in the image
IList<DetectedFace> detectedFaces =
faceClient.Face.DetectWithStreamAsync(imageStream).Result;
// Too many faces detected
if (detectedFaces.Count > 1)
{
name = string.Empty;
return 0;
}
IList<Guid> faceIds = detectedFaces.Select(f => f.FaceId.Value).ToList();
// Identify faces
IList<IdentifyResult> identifiedFaces =
faceClient.Face.IdentifyAsync(faceIds, "<Person Group ID>").Result;
// No faces identified
if (identifiedFaces.Count == 0)
{
name = string.Empty;
return 0;
}
// Get the first candidate (candidates are ranked by confidence)
IdentifyCandidate candidate =
identifiedFaces.Single().Candidates.FirstOrDefault();
// Find the person
Person person =
faceClient.PersonGroupPerson.GetAsync("", candidate.PersonId).Result;
name = person.Name;
return candidate.Confidence;
}
まず、サブスクリプション キーと API エンドポイントを渡すことにより、Face API 用のクライアント オブジェクトを取得する必要があります。どちらの値も Azure portal で取得できます。Face API サービスをプロビジョニングしたのもここでした。その後で、クライアントの Face オブジェクトの DetectWithStreamAsync メソッドにストリームとして渡された画像に現れている顔を検出します。Face オブジェクトは、Face API の認識と認証の操作を実装します。検出された顔のうち、実際には 1 つだけを検出して、その ID を取得するようになっています。これは、その会場に入場できる、認可されたすべての人物の登録済みの顔コレクションの中の、一意識別子です。その後、PersonGroup 内で検出された顔の識別を IdentifyAsync メソッドが実行し、最良の一致、つまり候補を信頼度レベル順に並べ替えたリストを返します。最初の候補の人物 ID を使用して人物名を取得します。この名前は、最終的に Access Web API に返されます。これで、顔認可要件が満たされます。
音声認識
Azure Cognitive Services Speaker Recognition API は、話者認証と話者識別用のアルゴリズムを提供します。音声には、指紋と同じように、人物を識別するために使用可能な一意の特性があります。この記事のセキュリティ ソリューションでは、音声を入場制御用の信号として使用します。ここでは、被験者が IoT デバイスとして登録されたマイクに向かってパス フレーズを発音します。顔認識と同様に、音声認識にも、認可された人物の事前登録が必要です。Speaker API では、登録される人物を「プロファイル」と呼びます。 プロファイルの登録時に、特定のフレーズを発音している話者の音声が録音され、次いでさまざまな特徴が抽出され、選択されたフレーズが認識されます。抽出された特徴と選択されたフレーズの両方が一緒になって、独自の声紋を形成します。認証中は、入力された音声とフレーズが、登録の声紋とフレーズに照らして比較され、それらが同じ人物のものかどうかと、フレーズが正しいかどうかが確認されます。
コード実装から判断して、Speaker API は、Face API のように NuGet 内のマネージド パッケージから恩恵を受けてはいないため、使用するアプローチは、HTTP クライアントの要求/応答メカニズムを使用して直接 REST API を呼び出す方法にします。最初の手順は、認証とデータ型に必要なパラメーターを使用して HttpClient をインスタンス化することです。
public VoiceRecognition()
{
_httpClient = new HttpClient();
_httpClient.BaseAddress = new Uri("<API Endpoint>");
_httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key",
"<Subscription Key>");
_httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
図 6 の Recognize メソッドは、次のように、いくつかの手順で動作します。会場の IoT デバイスからオーディオ ストリームを取得したら、登録済みのプロファイルのコレクションに照らして、その音声の識別を試みます。識別は、IdentifyAsync メソッド内にコード化されています。この非同期メソッドは、オーディオ ストリームと識別プロファイル ID を含むマルチパート要求メッセージを準備し、特定のエンドポイントに POST 要求を送信します。API からの応答が HTTP コード 202 (受理) の場合、返される値はバックグラウンドで実行される操作の URI です。指定された URI でこの操作は Recognize メソッドによって 100 ミリ秒ごとにチェックされて、完了に至ります。成功すると、識別された人物のプロファイル ID が取得されます。この ID を使用して、オーディオ ストリームの認証に進むことができます。この認証が、録音された音声が識別された人物のものであることの最終確認になります。これは、VerifyAsync メソッド内に実装されています。このメソッドは IdentifyAsync メソッドと同様に動作しますが、VoiceVerificationResponse オブジェクトを返すという点が異なります。このオブジェクトには、人物のプロファイルとその名前が含まれています。認証応答には信頼度レベルが含まれています。これも Face API と同様に、Access Web API に返されます。
図 6 音声認識
public double Recognize(string siteId, out string name)
{
ReadAudioStream(siteId, out Stream audioStream);
Guid[] enrolledProfileIds = GetEnrolledProfilesAsync();
string operationUri =
IdentifyAsync(audioStream, enrolledProfileIds).Result;
IdentificationOperation status = null;
do
{
status = CheckIdentificationStatusAsync(operationUri).Result;
Thread.Sleep(100);
} while (status == null);
Guid profileId = status.ProcessingResult.IdentifiedProfileId;
VoiceVerificationResponse verification =
VerifyAsync(profileId, audioStream).Result;
if (verification == null)
{
name = string.Empty;
return 0;
}
Profile profile = GetProfileAsync(profileId).Result;
name = profile.Name;
return ToConfidenceScore(verification.Confidence);
}
この API に関するいくつかの付加的なコメントによって、Face API との違いを示したいと思います。音声認証 API は、認証操作の全体的な結果 (許可または拒否)、信頼度レベル (低、標準、高)、および認識されたフレーズを含む JSON オブジェクトを返します。
{
"result" : "Accept", // [Accept | Reject]
"confidence" : "Normal", // [Low | Normal | High]
"phrase": "recognized phrase"
}
このオブジェクトは、VerifyAsync メソッド内での操作を容易にするために VoiceVerificationResponse C# クラスにマップされますが、その信頼度レベルはテキストとして表現されます。
public class VoiceVerificationResponse
{
[JsonConverter(typeof(StringEnumConverter))]
public Result Result { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public Confidence Confidence { get; set; }
public string Phrase { get; set; }
}
しかし、Access Web API は 0 と 1 の間の 10 進値 (倍精度データ型) を想定しているため、Confidence 列挙体に数値を指定しました。
public enum Confidence
{
Low = 1,
Normal = 50,
High = 99
}
その後、これらの値を倍精度に変換してから、Access Web API に戻るようになっています。
private double ToConfidenceScore(Confidence confidence)
{
return (double)confidence / 100.0d;
}
まとめ
以上がこの記事の最初の部分です。会場への入場のセキュリティ フロー全体について説明し、カスタム ポリシーと要件を使用した ASP.NET Core Web API の認可メカニズムの実装を取り上げました。次に、事前に認可または登録された人物のプロファイルの生体認証情報に基づいて入場を制限するメカニズムとして、関連する Cognitive Services API を使用した顔認識と音声認識について説明しました。2 番目の部分では、入場を要求するトリガー ポイントとして IoT デバイスからのデータ ストリーム配信を検討し、入場ドアをロック解除 (またはロック) するための Access API からの最終確認へと進みます。また、入場の試みが行われるたびに実行されてリスクを識別する、機械学習ベースの異常検出サービスを取り上げます。
このソリューションの最初の部分のソース コードは bit.ly/2IXPZCo にある GitHub から入手できます。
Stefano Tempesta氏は、マイクロソフト リージョナル ディレクターであり、AI およびビジネス アプリケーションの MVP であり、Blockchain Council のメンバーでもあります。Microsoft Ignite や Tech Summit などの国際的な IT 会議の常連の講演者である Tempesta の興味は、ブロックチェーンと AI 関連のテクノロジにまで広がっています。彼は、ブロックチェーン テクノロジに関するブログの Blogchain Space (blogchain.space) を立ち上げ、MSDN Magazine と MS Dynamics World に寄稿し、Azure AI Gallery (gallery.azure.ai) で機械学習の実験を公開しています。
この記事のレビューに協力してくれたマイクロソフト技術スタッフの Barry Dorrans 氏に心より感謝いたします。