アップデート:
JWTに関心のある人のために、 ASP.NETWebAPIにJWT認証を使用する方法を他の回答に追加しました。
HMAC認証をセキュリティで保護されたWebAPIに適用することができましたが、問題なく機能しました。HMAC認証では、コンシューマーとサーバーの両方がメッセージをhmacハッシュすることを知っているコンシューマーごとに秘密鍵を使用します。HMAC256を使用する必要があります。ほとんどの場合、コンシューマーのハッシュ化されたパスワードが秘密鍵として使用されます。
メッセージは通常、HTTPリクエストのデータ、またはHTTPヘッダーに追加されたカスタマイズされたデータから作成されます。メッセージには次のものが含まれる場合があります。
- タイムスタンプ:リクエストが送信された時刻(UTCまたはGMT)
- HTTP動詞:GET、POST、PUT、DELETE。
- 投稿データとクエリ文字列、
- URL
内部的には、HMAC認証は次のようになります。
コンシューマーは、HTTP要求のテンプレートである署名(hmacハッシュの出力)を構築した後、HTTP要求をWebサーバーに送信します。
User-Agent: {agent}
Host: {host}
Timestamp: {timestamp}
Authentication: {username}:{signature}
GETリクエストの例:
GET /webapi.hmac/api/values
User-Agent: Fiddler
Host: localhost
Timestamp: Thursday, August 02, 2012 3:30:32 PM
Authentication: cuongle:LohrhqqoDy6PhLrHAXi7dUVACyJZilQtlDzNbLqzXlw=
署名を取得するためにハッシュするメッセージ:
GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
クエリ文字列を使用したPOSTリクエストの例(以下の署名は正しくありません。単なる例です)
POST /webapi.hmac/api/values?key2=value2
User-Agent: Fiddler
Host: localhost
Content-Type: application/x-www-form-urlencoded
Timestamp: Thursday, August 02, 2012 3:30:32 PM
Authentication: cuongle:LohrhqqoDy6PhLrHAXi7dUVACyJZilQtlDzNbLqzXlw=
key1=value1&key3=value3
署名を取得するためにハッシュするメッセージ
GET\n
Thursday, August 02, 2012 3:30:32 PM\n
/webapi.hmac/api/values\n
key1=value1&key2=value2&key3=value3
フォームデータとクエリ文字列は順番に並んでいる必要があるため、サーバー上のコードはクエリ文字列とフォームデータを取得して正しいメッセージを作成することに注意してください。
HTTPリクエストがサーバーに到着すると、認証アクションフィルターが実装され、リクエストを解析して情報(HTTP動詞、タイムスタンプ、uri、フォームデータ、クエリ文字列)を取得し、これらに基づいてシークレットを使用して署名を作成します(hmacハッシュを使用)。サーバー上のキー(ハッシュされたパスワード)。
秘密鍵は、リクエスト時にユーザー名を使用してデータベースから取得されます。
次に、サーバーコードは、リクエストの署名と作成された署名を比較します。等しい場合は認証に合格し、そうでない場合は失敗します。
署名を作成するためのコード:
private static string ComputeHash(string hashedPassword, string message)
{
var key = Encoding.UTF8.GetBytes(hashedPassword.ToUpper());
string hashString;
using (var hmac = new HMACSHA256(key))
{
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
hashString = Convert.ToBase64String(hash);
}
return hashString;
}
では、リプレイ攻撃を防ぐ方法は?
次のようなタイムスタンプの制約を追加します。
servertime - X minutes|seconds <= timestamp <= servertime + X minutes|seconds
(servertime:サーバーにリクエストが到着する時間)
そして、リクエストの署名をメモリにキャッシュします(MemoryCacheを使用し、制限時間内に保持する必要があります)。次のリクエストに前のリクエストと同じ署名が付いている場合、そのリクエストは拒否されます。
デモコードは次のように配置されます:
https ://github.com/cuongle/Hmac.WebApi