1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ASP.NET CoreのCSRF対策周りのメモ

Last updated at Posted at 2020-06-06

.NET CoreのCSRF対策周りのメモ

CSRF対策回りのソースを読んだのでメモ

調べたバージョンはASP.NET Core 3.1

DIコンテナに関連するクラスを登録する方法

Startup.csservices.AddMvcservices.AddControllersWithViewsを実行すると登録が実行される

順にソースを追いかけていくと
MvcServiceCollectionExtensionsMvcViewFeaturesMvcCoreBuilderExtensions.AddViews が実行される

その先ではAddViewServices が実行されここAntiforgeryServiceCollectionExtensions.AddAntiforgeryを呼び出しており、この中でDIコンテナへのクラスの登録が実行されている。

インターフェース自体がinternal であるものも含まれており拡張の際は注意する必要がありそう。

トークン発行

CSRFトークンの発行は IAntiforgery をインジェクションし GetAndStoreTokens メソッドを実行すると CSRF用のリクエストトークンとクッキートークンが発行され、クッキートークンはクッキーに保存される。
(.cshtml でもこの方法で実装されていた気がする...)

GetTokens メソッドはクッキートークンは生成されるが、クッキーへの保存は行わない。
(何のために使うんだろ?)

以下順を追ってみていく

ソースのメモ

発行は実装クラスのDefaultAntiforgery.GetAndStoreTokensで行う

GetTokensInternal メソッドを呼び出しその中では GetCookieTokens を呼び出しており
その結果をSerialize メソッドで加工している

クッキートークンが新しく生成されていれば、クッキーに保存している

そんな感じ...

GetCookieTokens メソッド

ここ

GetAntiforgeryFeature はインスタンスの生成or再利用をしている感じかな?

そしてGetCookieTokenDoesNotThrow を呼んでいる。この中ではDefaultAntiforgeryTokenStore .GetCookieTokenを呼び出しており、(トークン取得後の2回目以降のリクエストなどで)Cookieにすでにクッキートークン が送信されていれば、それを取り出している

クッキートークンが送信されておりそれがトークン用の物として正しいものであれば再利用し、そうでなければ新しくクッキートークンの生成を行う
このへん

このあとは GetTokensInternal で結果を受け取り、クッキートークンをもとにリクエストトークンを生成する。

リクエストトークンの生成はIAntiforgeryTokenGenerator.GenerateRequestToken メソッドで行う

IAntiforgeryTokenGenerator.GenerateRequestTokenメソッド

実装はこちら

リクエストトークンを生成しているが構成要素はクッキートークンだけではなく、認証情報も含んでいる。

GetAuthenticatedIdentityClaimsIdentity を取得しており、取得できた場合はIClaimUidExtractor.ExtractClaimUid で認証済ユーザーを特定できるものをとってきているようだ。(後述)

もしIAntiforgeryAdditionalDataProvider があれば「追加データ」としてそれも構成要素に含めることができるようだ。(デフォルト実装は空文字列を返しているだけなので実質何もしていない)

IClaimUidExtractor.ExtractClaimUid メソッド

実装はこちら

ぱっと見た感じsub というクレーム名や ClaimTypes.NameIdentifierClaimTypes.Upn のクレームが見つかればそれを利用しており それも見つからなければ認証済の全クレームを使っているのかな?

Serializeメソッド

ここ

リクエストトークン、クッキートークンを加工しAntiforgeryTokenSet を作っているだけ

トークンの検証

トークンの検証はAutoValidateAntiforgeryTokenAttributeValidateAntiForgeryTokenAttributeを適用することで検証が行われる。

いずれの場合もここIAntiforgery.ValidateRequestAsync が実行されることで検証が行われる。

以下順を追ってみていく

ソースのメモ

検証は実装クラスのDefaultAntiforgery.ValidateRequestAsyncで行う

IAntiforgeryTokenStore.GetRequestTokensAsync でリクエストトークンとクッキートークンを取り出している。

クッキートークン、リクエストトークンともに無ければ例外を投げている。

そのあとValidateTokens メソッドから IAntiforgeryTokenGenerator.TryValidateTokenSet を実行し検証

検証NGならAntiforgeryValidationException をスローしている

IAntiforgeryTokenStore.GetRequestTokensAsync

実装はこちら

Cookie からクッキートークンを リクエストヘッダーからリクエストトークンを取り出している。

フォームから取り出すこともある。

そして結果をAntiforgeryTokenSet として返す

IAntiforgeryTokenGenerator.TryValidateTokenSet

実装はこちら

前半部分 ここらへんまではリクエストトークンとクッキートークンが一致してるとかのチェックだと思う

そこから先は HttpContext ,リクエストトークン それぞれから取得した認証情報や追加データなどが一致しているかを検証している感じかな?

ソースを読んでみて

リクエストトークンにはユーザーの認証関係の情報が含まれていることが確認できた。
このため認証前に取得したリクエストトークンが認証後に使用できないことも納得ができる。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?