ハッシュベースのメッセージ認証コード (HMAC) は、秘密キーと組み合わせたハッシュ関数を含むメッセージ認証コードを計算するメカニズムです。これは、メッセージの整合性と信頼性を検証するために使用できます。
この実装は、アマゾン ウェブ サービスで使用される主要な認証方法 (AWS Signature V4) から大きく影響を受けており、よく理解されており、それを実装するライブラリが多数あります。この形式の認証を使用するには、キー識別子と秘密キーを利用します。通常、これらはどちらも管理インターフェイスで生成されます。
HmacAuthentication は、ASP.NET Core プロジェクトで HMAC 認証をサポートするAuthenticationHandler
を提供します。
使用法:
appsettings.json
ファイルなどから取得します。 HMAC 認証の場合、アクセスするクライアントごとにAppId
とApiKey
が必要です。 var hmacAuthenticatedApps = this . Configuration
. GetSection ( " Authentication " )
. GetSection ( " HmacAuthenticatedApps " )
. Get < HmacAuthenticationClientConfiguration [ ] > ( )
. ToDictionary ( e => e . AppId , e => e . ApiKey ) ;
{
"Authentication" : {
"HmacAuthenticatedApps" : [
{
"AppId" : " <some-app-id> " ,
"ApiKey" : " <some-api-key> "
}
]
}
}
Startup.cs
のConfigureServices
メソッドで HMAC 認証を有効にします。 services
. AddAuthentication ( o =>
{
o . DefaultScheme = HmacAuthenticationDefaults . AuthenticationScheme ;
} )
. AddHmacAuthentication ( HmacAuthenticationDefaults . AuthenticationScheme , " HMAC Authentication " , o =>
{
o . MaxRequestAgeInSeconds = HmacAuthenticationDefaults . MaxRequestAgeInSeconds ;
o . HmacAuthenticatedApps = hmacAuthenticatedApps ;
} ) ;
ConfigureServices
メソッドのStartup.cs
にMemoryCache
(Microsoft.Extensions.Caching.Memory から) を追加します。 MemoryCache
、リプレイ攻撃を決定するために HMAC AuthenticationHandler
によって使用されます。 services . AddMemoryCache ( ) ;
Startup.cs
のConfigure
メソッドで認証を有効にします。 app . UseAuthentication ( ) ;
[ Authorize ( AuthenticationSchemes = HmacAuthenticationDefaults . AuthenticationScheme ) ]
[ Route ( " api/[controller] " ) ]
public class HomeController : Controller
{
// ...
}
HmacAuthenticaion は、HMAC 認証ヘッダーを HTTP リクエストに追加するためのDelegatingHandler
も提供します。
ApiKeyDelegatingHandler
を使用してHttpClient
インスタンスをインスタンス化します。リクエストごとに新しいHttpClient
インスタンスを作成しないようにしてください (詳細については、このブログ投稿も参照してください)。
new HttpClient ( new ApiKeyDelegatingHandler ( appId , apiKey ) ) ;
または、WebAPI クライアントが別の ASP.NET WebAPI (>= ASP.NET Core 2.1) の場合は、たとえば次のようにHttpClient
Startup.cs
に登録します。
services . AddTransient ( sp => new ApiKeyDelegatingHandler ( appId , apiKey ) ) ;
services
. AddHttpClient ( " HmacHttpClient " )
. AddHttpMessageHandler < ApiKeyDelegatingHandler > ( ) ;
API キーを生成するには、次の単純なコンソール アプリケーションを使用できます。この実装は .NET Fiddle でも提供されます。
using System . Security . Cryptography ;
public class Program
{
public static void Main ( )
{
Console . WriteLine ( $" AppID: { Guid . NewGuid ( ) } or <some-speaking-name> " ) ;
Console . WriteLine ( $" ApiKey: { GenerateApiKey ( ) } " ) ;
}
private static string GenerateApiKey ( )
{
using ( var cryptoProvider = new RNGCryptoServiceProvider ( ) )
{
byte [ ] secretKeyByteArray = new byte [ 32 ] ; //256 bit
cryptoProvider . GetBytes ( secretKeyByteArray ) ;
return Convert . ToBase64String ( secretKeyByteArray ) ;
}
}
}
セキュリティ リスクの最大の原因は通常、認証プロトコルではなく、その使用に関するポリシーと手順にあります。実装者は、このモジュールがセキュリティ要件にどのように対処するかを評価することを強くお勧めします。このセクションには、この認証プロトコルをサーバーに展開する前に確認して理解する必要があるセキュリティ上の考慮事項の不完全なリストが含まれています。仕様で提供される保護の多くは、それらが使用されるかどうか、またどのように使用されるかによって異なります。
HmacAuthentication は、必要な共有資格情報のセットを取得または送信するためのメカニズムを提供しません。 HmacAuthentication資格情報を取得するために使用されるメカニズムでは、これらの送信が TLS などのトランスポート層メカニズムを使用して保護されていることを確認する必要があります。
HmacAuthentication はHTTP リクエストの整合性を検証するメカニズムを提供しますが、リクエストの機密性は保証されません。他の予防策が講じられない限り、盗聴者はリクエストの内容に完全にアクセスできるようになります。サーバーは、そのようなリクエストの一部として送信される可能性のあるデータの種類を慎重に検討し、トランスポート層のセキュリティ メカニズムを採用して機密リソースを保護する必要があります。
HmacAuthentication は、サーバーの信頼性を限定的に検証します。サーバーから応答が返されたとき。
敵対的な当事者は、クライアントのリクエストを傍受し、誤解を招く、または不正確な応答を返すことによってこれを利用する可能性があります。サービス プロバイダーは、このプロトコルを使用するサービスを開発するときにそのような攻撃を考慮する必要があり、リソース サーバーまたはサーバー応答の信頼性が問題となるリクエストに対してトランスポート層のセキュリティを要求する必要があります。
HmacAuthenticationキーは、従来の認証システムにおけるパスワードと同じように機能します。リクエスト MAC を計算するには、サーバーが平文形式でキーにアクセスできる必要があります。これは、たとえば、ユーザー資格情報の一方向ハッシュのみを保存する最新のオペレーティング システムとは対照的です。
攻撃者がこれらのキーにアクセスした場合、さらに悪いことに、そのようなキーすべてが含まれるサーバーのデータベースにアクセスした場合、リソース所有者に代わってあらゆるアクションを実行できるようになります。したがって、サーバーがこれらのキーを不正アクセスから保護することが重要です。
トランスポート層セキュリティ プロトコルが使用されない限り、盗聴者は認証されたリクエストと MAC 値に完全にアクセスできるため、使用されたキーを回復するためにオフライン ブルート フォース攻撃を仕掛けることができます。サーバーは、少なくともHmacAuthentication資格情報が有効である期間にわたってそのような攻撃に耐えられるように、十分な長さとランダムなキーを割り当てるように注意する必要があります。
たとえば、資格情報が 2 週間有効な場合、サーバーは、2 週間未満でキーを回復するブルート フォース攻撃を仕掛けることができないことを保証する必要があります。もちろん、サーバーには慎重になって、合理的な最長のキーを使用することが求められます。
これらのキーの生成に使用される擬似乱数ジェネレーター (PRNG) が十分に高品質であることも同様に重要です。多くの PRNG 実装では、ランダムに見える数値シーケンスが生成されますが、それでも暗号解読やブルート フォース攻撃を容易にするパターンやその他の弱点が存在します。実装者は、これらの問題を回避するために、暗号的に安全な PRNG を使用するように注意する必要があります。
リクエスト MAC は、HTTP Host
ヘッダー、 Content-Type
ヘッダー、およびオプションで指定されたヘッダーのセットのみをカバーします。サーバーによるリクエスト本文の解釈方法に影響を与える可能性があるその他の未知のヘッダーはカバーしません。サーバーの動作がそのようなヘッダーの存在または値によって影響を受ける場合、攻撃者は検出されることなくリクエスト ヘッダーを操作する可能性があります。実装者は、 headers
機能を使用して、リクエスト MAC によって保護されているAuthorization
ヘッダーを介して署名に追加するヘッダーを渡す必要があります。署名ベース文字列は、これらの指定されたヘッダーを署名に追加して、MAC の一部にする役割を果たします。
応答認証が実行される場合、応答の本文 (ペイロード) と、タイムスタンプやナンスなどの要求でクライアントによって提供される一部の要求情報のみが対象となります。 HTTP ステータス コードや、クライアントの動作に影響を与える可能性のあるその他の応答ヘッダー フィールド (場所など) はカバーされません。
攻撃者がこの情報を操作して、クライアントに不正な時刻を使用させることができれば、将来、クライアントが時刻を使用して認証されたリクエストを生成する可能性があります。このようなリクエストはクライアントから送信されると失敗し、サーバー上に痕跡を残すことはほとんどありません (nonce の一般的な実装を考慮すると、たとえ強制されたとしても)。攻撃者は、検出されることなく、正しい時間にリクエストを再実行できるようになります。
この問題の解決策は、クライアントとサーバー間のクロック同期です。これを実現するために、サーバーは無効なタイムスタンプを受信したときにクライアントに現在時刻を通知します。これは、応答内の Date ヘッダーの形式で発生します。この動機については RFC2616 を参照してください。
クライアントは、次の場合にのみサーバーから提供される時刻情報を使用する必要があります。
不正なタイムスタンプを持つリクエストを受信すると、サーバーはクライアントに現在の時刻を提供します。クライアントは、サーバーから受信した時刻を自身のクロックを調整するために決して使用してはならず、その特定のサーバーと通信するためのオフセットを計算するためにのみ使用する必要があります。
HmacAuthentication は、受信リクエスト MAC を受信 HTTP ホスト ヘッダーと照合して検証します。悪意のあるクライアントは、サーバーの IP アドレスを指す新しいホスト名を作成し、それを使用して、サーバーで使用されているホスト名とは別のホスト名を対象とする有効なリクエストを送信することで攻撃を仕掛けることができます。サーバー実装者は、受信したホスト ヘッダーが期待どおりであることを手動で検証する必要があります。たとえば、test.myapi.com での API 呼び出しが予想される場合は、サーバー実装でリクエストが送信されたドメインがそのドメインであることを確認します。