今日は、今後の WebAPI プロジェクトに向けて、C# でのさまざまな HMAC 実装を調べることに時間を費やしました。ゼロから作成するか、必要に応じて変更する前に、すべてが機能することを確認し、理解を深めるために、既存のコードから始めたいと思いました。
こことウェブの両方に、素晴らしい記事や投稿がたくさんあります。しかし、私はいくつかの指針が必要であり、いくつかの洞察を大いに感謝するところまで来ました.
Cuong の投稿 ( ASP.NET Web API をセキュリティで保護する方法) から始めました。
json と formencoded データの両方をサポートしたかったので、拡張する必要があることはわかっていました。テスト クライアントも HttpClient を使用して C# で記述されており、空の WebAPI プロジェクトを作成し、ValuesController を使用しています。
以下は私の観察と質問です。
POSTing: Cuong のコードを機能させる (正常に検証する) には、POST で URL にパラメーターを含める必要がありますが、値をコントローラーに取得するには、それらを本体に含める必要があります。これは、このタイプの認証では正常ですか? この特定の例では、ハッシュしているメッセージは http://:10300/api/values?param1=value1¶m2=value2 です。これで、クエリ文字列を手動で解析して取得できますが、バインディングを通じてコントローラーに値を取得するには、次のことも行う必要があります。
var dict = new Dictionary<string, string> { {"param1", "value1"}, {"param2", "value2"} }; var content = new FormUrlEncodedContent(dict); var response = await httpClient.PostAsync(httpClient.BaseAddress, content);
それ以外の場合、ValuesController のポスト アクションでは、パラメーターは常に null です。
ノンスを含めるようにコードを拡張することを計画しています。ノンス、タイムスタンプ、および動詞の組み合わせで、安全なハッシュに十分でしょうか? メッセージもハッシュする必要は本当にありますか?
json とフォーム エンコードされたデータをサポートするようにコードを拡張しようとしましたが (非常に失敗しました)、明らかな何かが欠けているに違いありません。
Cuong は、署名とタイムスタンプをクエリ文字列に入れる代わりに、Authentication ヘッダーと Timestamp ヘッダーを使用しています。ある方法に他の方法よりも利点はありますか? 私が読んだ記事の大部分では、クエリ文字列自体にそれらが含まれています。
コードは見栄えがよく、ここで私の要素から少し外れています。ニュアンスを理解するためにゼロから書いた方が安全かもしれません(正気ですか?)。そうは言っても、私が見ているものに誰かが洞察を与えることができれば、それは素晴らしいことです.
結局のところ、WebAPI フレームワークの組み込みの承認メカニズムを使用して、メソッド/コントローラーを単純に属性付けし、エンコードされたフォームと json データを受け入れ、複雑な型の合理的なモデル バインドを行えるようにしたいと考えています。
* アップデート *
今日はさらに作業を行いました。以下は、nUnit PostTest のコードです。本文とクエリ文字列の両方に値を含めずに値を取得する方法を見つけました(以下のコード)。
[Test]
public async void PostTest()
{
using (var httpClient = new HttpClient())
{
var payload = new FormUrlEncodedContent(new Dictionary<string, string>
{
{"key1", "value1"},
{"key2", "value2"}
});
var now = DateTime.UtcNow.ToString("U");
httpClient.BaseAddress = new Uri(string.Format("http://ipv4.fiddler:10300/api/values"));
httpClient.DefaultRequestHeaders.Add("Timestamp", now);
httpClient.DefaultRequestHeaders.Add("Authentication", string.Format("test:{0}", BuildPostMessage(now, httpClient.BaseAddress, await payload.ReadAsStringAsync())));
var response = await httpClient.PostAsync(httpClient.BaseAddress, payload);
await response.Content.ReadAsStringAsync();
Assert.AreEqual(true, response.IsSuccessStatusCode);
}
}
また、そのモデル バインディング部分も把握しました。ここにすばらしい記事があります: http://www.west-wind.com/weblog/posts/2012/Mar/21/ASPNET-Web-API-and-Simple-Value-Parameters-from-POSTed-dataについて説明していますPOST がどのように機能するかを説明し、自分で設計したモデルと FormDataCollection オブジェクトの両方で動作させることができました。
今、jsonでエンコードされたメッセージを追加する価値があるかどうか、または FormUrlEncoding で標準化することが道であるかどうか疑問に思っています。また、クライアントの通知で十分ですか、それともサーバー側の通知を実装する必要がありますか? サーバー側の通知は、サービスへのすべての呼び出しを 2 倍にしますか (最初の呼び出しは 401 をスローし、2 番目の呼び出しは通知と共にペイロードを含みますか?