web-dev-qa-db-ja.com

Asp.net Core Web APIリソースベースの承認、コントローラーレベル外

他のアプリケーションと同様に、ユーザーAがユーザーBのリソースにアクセスできないようにして、さまざまなロールを持つユーザーでWeb APIを作成しています。以下のように:

注文/ 1(ユーザーA

注文/ 2(ユーザーB

もちろん、リクエストからJWTを取得し、データベースにクエリを実行して、このユーザーがその注文を所有しているかどうかを確認することもできますが、コントローラーアクションが重くなります。

この はAuthorizeAttributeを使用していますが、範囲が広すぎるようです。APIのすべてのルートに多数の条件を追加して、アクセスされているルートを確認し、データベースにクエリを実行して、いくつかの結合を行って、戻るようにします。リクエストが有効かどうかを返すために、usersテーブルに追加します。

更新

ルートの場合、防御の第一線は、特定の要求を必要とするセキュリティポリシーです。

私の質問は、ユーザーが自分のデータ/リソースにのみアクセスすることを確実にする責任がある第二の防衛線についてです。

このシナリオで採用する標準的なアプローチはありますか?

9

答える必要がある最初の質問は、「いつこの許可決定を行うことができるか」です。チェックを行うために必要な情報はいつ実際にありますか?

ほとんど常にルートデータ(または他の要求コンテキスト)からアクセスされているリソースを特定できる場合、 一致する要件とハンドラーを持つポリシー が適切です。これは、リソースでサイロ化されたデータを操作している場合に最適に機能します。リストのフィルタリングなどにはまったく役立ちません。これらの場合は、強制チェックにフォールバックする必要があります。

実際に検討するまで、ユーザーがリソースをいじることができるかどうかを実際に理解できない場合は、命令型チェックにかなりこだわっています。これには 標準フレームワーク がありますが、ポリシーフレームワークほど有用ではありません。これらのフィルターのいくつかをカプセル化する__reable_name__をドメインに照会するときに(つまり、repos/where linqを使用して)挿入できるIUserContextを書くことは、おそらく価値があるでしょう(IEnumerable<Order> Restrict(this IEnumerable<Order> orders, IUserContext ctx))。

複雑なドメインの場合、簡単な特効薬はありません。 ORMを使用すると役立つ場合がありますが、ドメイン内のナビゲート可能な関係により、特に集計を分離したままにしようとしない場合(myOrder.Items [ n] .Product.Orderees [notme] ...)。

前回これを行ったとき、90%のケースでルートベースのポリシーベースのアプローチを使用することができましたが、それでも奇数のリストまたは複雑なクエリに対していくつかの手動の必須チェックを実行する必要がありました。命令型チェックを使用する際の危険は、ご存じのとおり、チェックを忘れてしまうことです。これの潜在的な解決策は、コントローラレベルで[Authorize(Policy = "MatchingUserPolicy")]を適用し、アクションに追加のポリシー「ISolemlySwearIHaveDoneImperativeChecks」を追加してから、MatchUserRequirementsHandlerでコンテキストを確認し、次の場合に単純なユーザー/順序の一致チェックをバイパスすることです強制チェックは「宣言」されています。

1
Mark Churchill

あなたの発言は間違っており、あなたもそれを間違って設計しています。

過剰最適化はすべての悪の根源です

このリンクは、「機能しないと主張する前にパフォーマンスをテストする」で要約できます。

ID(jwtトークンまたは構成したもの)を使用して、実際のユーザーが適切なリソースにアクセスしているかどうか(または、所有しているリソースだけを提供した方がよい)を確認します。重くなった場合は、何か問題があります。大量の同時アクセスがあり、ディクショナリのorder-> owneridが時間とともにクリアされるなど、一部のデータをキャッシュするだけでよい場合がありますが、そうではありません。

設計について:インジェクトでき​​る再利用可能なサービスを作成し、ユーザー(IdentityUser、またはjwtサブジェクト、ユーザーIDのみ、または何でもかまいません)を受け入れる必要なすべてのリソースにアクセスするメソッドを用意します。

何かのようなもの

ICustomerStore 
{
    Task<Order[]> GetUserOrders(String userid);
    Task<Bool> CanUserSeeOrder(String userid, String orderid);
}

適宜実装し、このクラスを使用して、ユーザーがリソースにアクセスできるかどうかを体系的にチェックします。

1
L.Trabacchin