「ユーザーは管理者かどうかを判断すべきではありません。特権またはセキュリティシステムが必要です。」


55

質問で使用されている例では、最小限のデータを関数渡し、ユーザーが管理者であるかどうかを判断するための最良の方法に触れています。一般的な答えは次のとおりです。

user.isAdmin()

これにより、コメントが何度か繰り返され、何度も投票されました。

ユーザーは、管理者であるかどうかを決定するべきではありません。特権またはセキュリティシステムが必要です。クラスに密接に結合されているからといって、それをそのクラスの一部にすることは良い考えではありません。

私は答えた、

ユーザーは何も決定していません。ユーザーオブジェクト/テーブルには、各ユーザーに関するデータが格納されます。実際のユーザーは、自分に関するすべてを変更することはできません。

しかし、これは生産的ではありませんでした。明らかに、遠近法には根本的な違いがあり、それがコミュニケーションを難しくしています。誰かがuser.isAdmin()が悪い理由を説明し、それが「正しく」行われたように見えるものの簡単なスケッチを描くことができますか?

本当に、私はそれが保護するシステムからセキュリティを分離することの利点を見ることはできません。セキュリティに関するテキストには、セキュリティを最初からシステムに組み込む必要があり、開発、展開、保守、さらには寿命のあらゆる段階で考慮する必要があると書かれています。側面にボルトで固定できるものではありません。しかし、このコメントに対するこれまでの17の賛成票は、私が重要な何かを見逃していると言っています。


8
特にユーザーdbテーブルのフラグだけの場合、私は悪いとは思いません。必要があり、今後の変化があって、将来的にそれを変更。ユーザーオブジェクトからセキュリティシステムを呼び出すこともできます。私は一度、すべてのdb / resourceアクセスがcurrent-userオブジェクトを通過する必要があるというデザインパターンについて読んだことがあります。少し多すぎるかもしれませんが、ユーザーはセキュリティ関連のものをすべてカバーする「特権」オブジェクトを提供できます。
頭足類

誤解があったと思います。あなたにとって、「ユーザー」とはソフトウェアを使用する人を意味します。彼らにとって、「ユーザー」とはあなたの機能を使用するコードを意味します。
フィリップ

2
あなたが尋ねたことではありませんが、この場合に私が最も注意することは、どこに置いてもIsAdmin()メソッドです。私は通常、「管理者」をハードコーディングせずに、可能なアクセス許可のセットのみを持ち、「管理者」がたまたまそのセット全体を持つことをお勧めします。こうすることで、後で管理者ロールを分割する必要があるときに、作業がはるかに簡単になります。そして、特別なケースのロジックを削減します。
psr

1
@Philipp私はそうは思わない...両方のサイトはUserisAdmin()メソッドを使用してオブジェクトについて明示的に話している(裏で行われていることは何でも)
Izkata

編集するには遅すぎます。「両方のサイト」ではなく「両側」を意味していました... = P-
イズカタ

回答:


12

ユーザーをキーとして、パーミッションを値として考えてください。

異なるコンテキストには、ユーザーごとに異なる権限があります。権限はコンテキストに関連しているため、コンテキストごとにユーザーを変更する必要があります。したがって、そのロジックを別の場所(コンテキストクラスなど)に配置し、必要に応じてアクセス許可を検索することをお勧めします。

副作用として、システムがより安全になる可能性があります。これは、関連性のない場所の管理フラグをクリアすることを忘れることができないためです。


40

そのコメントはひどい言葉でした。

ポイントは、ユーザーオブジェクトが、それは管理者、トライアルユーザー、スーパーユーザーまたはであるかどうかを「決定」するかどうかではないものや普通の。明らかにそれはそれらのことを決定するものではなく、あなたが実装しているソフトウェアシステム全体が決定します。ポイントは、「ユーザー」クラスがそのオブジェクトが表すプリンシパルの役割を表すべきか、またはこれが別のクラスの責任であるかどうかです。


6
痛い(それは私のコメントだった)が、あなたは私がやったよりもずっと良いと思う。
マルジャンヴェネマ

Userクラスではなく、別のRoleクラスでロールをモデル化すると言っていますか?LDAPのような別のシステムを推奨していませんか?Roleクラスが行うすべての決定が、適切なユーザーレコードのクエリを必要とし、他の情報を必要としない場合はどうなりますか?それでもユーザーから分離する必要がありますか?
グレンペターソン

2
@GlenPeterson:必ずしもそのクラス<>テーブルではなく、通常、テーブルよりも多くのクラスが識別されます。しかし、データ指向であることは、クラスのサブリストを定義することにつながりますが、これらのリストは、別の「元帳」(順序)または取得するユーザー(または順序)を渡すようなクラスで何度も定義する必要があります...動詞や名詞よりも責任の問題です。
マルジャンヴェネマ

9
ユーザーをキーとして、パーミッションを値として考えてください。異なるコンテキストには、ユーザーごとに異なる権限があります。権限はコンテキストに関連しているため、コンテキストごとにユーザーを変更する必要があります。そのため、そのロジックを別の場所(コンテキストクラスなど)に配置することをお勧めします。
ウィルバート

2
@ウィルバート:コンテキスト!それは特に啓発的です!はい、それらのアクセス許可に対して複数のコンテキストがある場合、すべてが理にかなっています。通常、これらの権限は単一のコンテキストで表示されます。その場合、ユーザーに付与するのが最も簡単なソリューションです。2番目のコンテキストで異なる方法で適用する場合、明らかにそれらはそこに属しません。あなたが答えとしてそれを書いたら、私はそれを受け入れるでしょう。ありがとうございました。
グレンペターソン

30

私は元のコメントを言葉どおりに表現することを選択しませんでしたが、正当な問題の可能性を特定します。

特に、分離を保証する懸念は、認証認可です。

認証とは、ログインしてIDを取得するプロセスを指します。それは、システムがあなたがであるかを知る方法であり、パーソナライゼーション、オブジェクト所有権などのようなものに使用されます。

承認許可されていることを指し、これは(一般に)あなたが誰であるかによって決まりません。代わりに、ロールや権限などのセキュリティポリシーによって決定されます。これらのポリシーは、名前やメールアドレスなどを気にしません。

これら2つは、互いに直交して変化します。たとえば、OpenID / OpenAuthプロバイダーを追加して認証モデルを変更できます。また、新しいロールを追加するか、RBACからABACに変更することにより、セキュリティポリシーを変更できます。

これらすべてが1つのクラスまたは抽象化になると、リスクを軽減するための最も重要なツールの1つであるセキュリティコードが皮肉なことに高リスクになります。

私は、認証と承認があまりにも密に結合されているシステムで働いてきました。1つのシステムでは、それぞれが1つのタイプの「ロール」に対応する2つの並列ユーザーデータベースがありました。それを設計した人またはチームは、明らかに、単一の物理ユーザーが両方の役割を担っていること、複数の役割に共通する特定のアクションがあること、またはユーザーIDの衝突に問題があるとは考えていませんでした。これは明らかに極端な例ですが、作業するのは非常に苦痛でした。

MicrosoftおよびSun / Oracle(Java)は、認証および許可情報の集合体セキュリティプリンシパルと呼びます。完璧ではありませんが、かなりうまく機能します。.NETでは、たとえば、あなたが持ってIPrincipalいる、カプセル化IIdentity前者は- ポリシー(承認)オブジェクトを、後者がある一方、アイデンティティ(認証)。あるものを別のもののに入れるという決定に合理的に疑問を投げかけることはできますが、重要なことは、あなたが書くほとんどのコードは抽象化の1つだけのためであり、テストとリファクタリングが容易であることを意味します。

User.IsAdminフィールドに問題はありません... フィールドもある場合を除きUser.Nameます。これは、「ユーザー」の概念が適切に定義されていないことを示します。これは、残念ながら、セキュリティに関して少し遅れている開発者の間で非常によくある間違いです。通常、IDポリシーで共有する必要があるのはユーザーIDだけです。これは、偶然ではなく、Windowsと* nixの両方のセキュリティモデルでの実装方法です。

IDとポリシーの両方をカプセル化するラッパーオブジェクトを作成することは完全に受け入れられます。たとえば、現在のユーザーがアクセスを許可されているさまざまなウィジェットまたはリンクに加えて、「hello」メッセージを表示する必要があるダッシュボード画面の作成を容易にします。このラッパーがIDおよびポリシー情報をラップするだけで、所有権を主張しない限り。言い換えれば、集約ルートとして提示されていない限り。

単純なセキュリティモデルは、YAGNIなどの理由で、新しいアプリケーションを最初に設計するときは常に良いアイデアのように見えますが、ほとんどの場合、新しい機能が追加されるので、ほとんどの場合、後で噛み付いてしまいます。

そのため、自分に最適なものがわかっている場合は、認証情報と承認情報を別々に保持します。現在の「承認」が「IsAdmin」フラグと同じくらい簡単な場合でも、認証情報と同じクラスまたはテーブルの一部でない場合は、セキュリティポリシーが必要な場合に変更すると、認証システムで再建手術を行う必要はありませんが、すでに正常に機能しています。


11
ああ、これを書く時間があったらいいのに。繰り返しになりますが、私はおそらくあなたが私の側でより多くの思考なしにそれを置くことができなかったでしょう。多くの場合、私の直感は何らかの方法で進むように私に言いますが、その理由-自分自身または他の誰かに-を説明するには、より多くの思考と努力が必要です。この投稿をありがとう。ですが、それを、複数のplussedているが、SEは...私をさせません
マージャンVenema氏

これは私が取り組んでいるプロジェクトと驚くほど似ているように思われ、あなたの答えは別の見方を与えてくれました。どうもありがとうございます!
ブランドン

「User.IsAdminフィールドには何も問題はありません... User.Nameフィールドもなければ」と書いています。しかしisAdmin、メソッドとは何ですか?権限を追跡することを担当するオブジェクトに委任するだけの場合もあります。リレーショナルモデルの設計におけるベストプラクティスであるもの(エンティティのフィールド)は、必ずしもOOモデルのベストプラクティスであるもの(オブジェクトが応答できるメッセージ)に翻訳できるとは限りません。
KaptajnKold

@KaptajnKold:このフォーラムのさまざまなQ&Aスレッドでこの感情を読み続けています。メソッドが存在する場合、操作を直接実行するか、それを委任するかは問題ではありませんが、他のクラスがそれに依存する可能性があるため、依然として責任としてカウントされます。あなたUser.IsAdminは、おそらくを呼び出すだけのワンライナーであるかもしれませんがPermissionManager.IsAdmin(this.Id)、それが他の30のクラスによって参照される場合、それを変更または削除することはできません。それがSRPが存在する理由です。
アーロンノート

そして、@ KaptajnKold、リレーショナルモデルに関する限り、あなたが何を得ているのかわかりません。フィールドを持つことはさらに悪いことです。これは、システムがRBACまたはより複雑なものに進化してからずっと長く続く傾向があり、「実際の」アクセス許可と徐々に同期しなくなる傾向があり、人々はもはやそれを使うべきではないことを忘れてしまい、そして...まあ、ただノーと言う。「admin」と「non-admin」の2つのロールしかない場合でも、ブール/ビットフィールドとして保存せず、適切に正規化し、許可テーブルを用意してください。IsAdmin
アーロンノート

28

まあ、少なくともそれは単一の責任原則に違反しています。変更(複数の管理レベル、さらに異なるロール)があるはずです。この種の設計はかなり面倒で、維持するのが大変です。

セキュリティシステムをユーザークラスから分離する利点を検討してください。これにより、両方が単一の適切に定義された役割を持つことができます。全体的に、よりクリーンで保守しやすい設計になります。


2
@GlenPeterson:いいえ、ユーザーはセキュリティなしで非常によく存在できます。私の名前、表示名、住所、電子メールアドレスなどはどうですか。どこに置きますか?識別(認証)と承認はまったく異なるものです。
マルジャンヴェネマ

2
class Userは、識別、認証、承認のセキュリティトリプレットのコアコンポーネントです。これらは設計レベルで密接に結びついているため、この相互依存性をコードが反映するのは不合理ではありません。
-MSalters

1
問題は、Userクラスにトリプレットを処理するためのすべてのロジックが含まれているかどうかです。
ザビエル

3
@MSalters:そのようなロジックのAPIである場合、他の場所に正確なロジックを委任する場合でも、そのことを認識します。行われているポイントは、承認(許可)はユーザーと他の何かの組み合わせに関するものであり、したがってユーザーまたは他の何かの一部ではなく、ユーザーとその他の両方を正しく認識する許可システムの一部であるべきです許可が与えられています。
マルジャンヴェネマ

2
Should there be changes-まあ、私たちは変化があることを知りません。ヤグニとすべて。必要になったときに、これらの変更はありますか?
イズカタ

10

おそらく不十分に表現された問題は、それがUserクラスに過度の重みをかけていることだと思います。いいえ、User.isAdmin()これらのコメントで提案されているように、methodを使用してもセキュリティ上の問題はありません。結局のところ、コアクラスの1つに悪意のあるコードを挿入できるほど深くコードの誰かがいると、深刻な問題が発生します。一方、Userすべてのコンテキストの管理者であるかどうかを判断することは意味がありません。フォーラムのモデレーター、投稿をフロントページに公開できる編集者、編集者が公開するコンテンツを作成できるライターなど、さまざまな役割を追加するとします。Userオブジェクトにオブジェクトを配置するアプローチでUserは、クラスに直接関係しないメソッドとその上に存在するロジックが多すぎることになります。

代わりに、さまざまな種類のアクセス許可の列挙とPermissionsManagerクラスを使用できます。おそらくPermissionsManager.userHasPermission(User, Permission)、ブール値を返すのようなメソッドを持つことができます。実際には、次のようになります(Javaの場合):

if (!PermissionsManager.userHasPermission(user, Permissions.EDITOR)) {
  Site.renderSecurityRejectionPage();
}

これは、Railsのメソッドbefore_filterメソッドと本質的に同等であり、実世界でのこのタイプのアクセス許可チェックの例を提供します。


6
user.hasPermission(Permissions.EDITOR)オブジェクト指向ではなく、より冗長で手続き型であることを除いて、それはとどのように違いますか?
頭足類

9
@Arian:user.hasPermissionsユーザークラスに多くの責任を負わせるからです。ユーザーはパーミッションについて知る必要がありますが、ユーザー(クラス)はそのような知識がなくても存在できる必要があります。ユーザークラスにそれ自体を印刷または表示(フォームを構築)する方法を知らせたくない場合は、それをプリンターレンダラー/ビルダーまたはディスプレイレンダラー/ビルダークラスに任せます。
マルジャンヴェネマ

4
user.hasPermission(P)は正しいAPIですが、それはインターフェースにすぎません。もちろん、実際の決定はセキュリティサブシステムで行う必要があります。テストに関するシリオンのコメントに対処するために、テスト中にそのサブシステムを交換できます。ただし、簡単な利点は、user.hasPermission(P)テストできるようにすべてのコードを汚染しないことですclass User
–MSalters

3
@MarjanVenemaその論理により、ユーザーは一切の責任を負わずにデータオブジェクトのままです。このような複雑なシステムが必要な場合は、パーミッション管理全体をユーザークラスに実装する必要があるとは言っていません。ユーザーはアクセス許可について知る必要はないと言いますが、他のすべてのクラスがユーザーのアクセス許可を解決する方法を知る必要がある理由はわかりません。これにより、モックとテストがはるかに難しくなります。
頭足類

6
@Arian:貧血のクラスは匂いですが、一部のクラスにはまったく動作がありません...ユーザー、imhoは、他の多くのもの(何かをしたい人)のパラメーターとして使用する方が適切なクラスの1つです/誰がそれらを求めているかに基づいて決定する)、そのようにコーディングするのが便利だと思われるからといって、あらゆる種類の動作のコンテナとして使用されるよりも。
マルジャンヴェネマ

9

Object.isX()は、オブジェクトとXの間の明確な関係を表すために使用されます。これは、たとえば次のようなブール値の結果として表現できます。

Water.isBoiling()

Circuit.isOpen()

User.isAdmin()は、システムのすべてのコンテキスト内で「管理者」という単一の意味を想定します。ユーザーは、システムのあらゆる部分で管理者です。

簡単に聞こえますが、実際のプログラムはほとんどこのモデルに適合しません。ユーザーが[X]リソースを管理し、[Y]ではなく、またはより明確なタイプの管理者([プロジェクト]管理者と[システム]管理者)。

この状況では、通常、要件の調査が必要です。クライアントがUser.isAdmin()が実際に表す関係を必要とすることはめったにないので、明確化せずにそのようなソリューションを実装することをheします。


6

ポスターは単に異なる、より複雑なデザインを念頭に置いていました。 私の意見でUser.isAdmin()は、大丈夫です。後で複雑な許可モデルを導入したとしても、移動する理由はほとんどありませんUser.isAdmin()。後で、Userクラスを、ログインしているユーザーを表すオブジェクトと、ユーザーに関するデータを表す静的オブジェクトに分割できます。または、そうでないかもしれません。明日のために明日保存します。


4
Save tomorrow for tomorrow。うん。書いたばかりの密結合コードがピジョンホールになっていることがわかったら、それを切り離すのに余分な20分はかからなかったので書き直さなければなりません...
MirroredFate

5
@MirroredFate:User.isAdminUserクラスを特定のメカニズムに結合することなく、メソッドを任意の許可メカニズムに接続することは完全に可能です。
ケビンクライン

3
User.isAdminを任意の許可メカニズムに結合するには、特定のメカニズムに結合しなくても、...結合...が必要です。最小はインターフェイスに対するものです。そして、そのインターフェースは単に存在するべきではありません。ユーザークラス(およびインターフェイス)に、単に責任を負わせないものを提供します。アーロンノートは、私ができるよりもずっとうまく説明しています(この質問に対する他のすべての答えの組み合わせもそうです)。
マルジャンヴェネマ

8
@MirroredFate:より複雑な要件を満たすために単純な実装を書き換える必要があるかどうかは気にしません。しかし、私は想像もしなかった将来の予想される要件を満たすように設計された過度に複雑なAPIで本当に悪い経験をしました。
ケビンクライン

3
@kevincline過度に複雑なAPIは(定義上)悪いことですが、過度に複雑なAPIを記述することを提案していませんでした。Save tomorrow for tomorrowシステムの実装がはるかに悪くなると些細な問題が発生するため、これはひどい設計アプローチであると述べました。実際、最初の貧弱なデザインを修正するためにレイヤーごとにレイヤーが追加されるため、その考え方が過度に複雑なAPIをもたらします。私は私の立場があると思いますmeasure twice, cut once
MirroredFate

5

本当に問題ない...

に問題はありませんUser.isAdmin()。私は確かにのようなものよりもそれを好む。それPermissionManager.userHasPermission(user, permissions.ADMIN)はSRPの神聖な名前でコードをより明確にせず、価値のあるものを追加しない。

私は、SRPが文字通りに少し解釈されていると思う。クラスにリッチなインターフェースを持たせることは望ましいことです。SRPは、オブジェクトが単一の責任に該当しないものはすべて、共同作業者に委任する必要があることを意味します。ユーザーの管理者ロールがブール型フィールドよりも複雑なものである場合、ユーザーオブジェクトがPermissionsManagerに委任することは非常に適切です。しかし、それは、ユーザーがisAdminメソッドを保持することも良い考えではないという意味ではありません。実際、アプリケーションが単純なものから複雑なものへと変化する場合、ユーザーオブジェクトを使用するコードを変更する必要があることを意味します。IOW、クライアントはユーザーが管理者であるかどうかの質問に答えるために本当に必要なことを知る必要はありません。

...しかし、なぜあなたは本当に知りたいのですか?

とはいえ、ユーザーがウィジェットの更新など、特定のアクションの実行を許可されているかどうかなど、他の質問に答えることができる以外は、ユーザーが管理者であるかどうかを知る必要はほとんどないようです。その場合、次のようなウィジェットのメソッドを使用したいと思いisUpdatableBy(User user)ます。

boolean isUpdatableBy(User user) {
    return user.isAdmin();
}

このように、ウィジェットは、ユーザーが更新するためにどの条件を満たす必要があるかを知る責任があり、ユーザーはそれが管理者であるかどうかを知る責任があります。この設計は、その意図を明確に伝え、その時が来たときに、より複雑なビジネスロジックに簡単に移行できるようにします。

[編集]

持っていないことUser.isAdmin()と使用していることの問題PermissionManager.userHasPermission(...)

ユーザーが管理者(または管理者ロール)であるかどうかを知りたい場合、PermissionManagerオブジェクトのメソッドを呼び出すよりもUserオブジェクトのメソッドを呼び出すことを非常に好む理由を説明するために答えに追加しようと思いました。

このユーザーが管理者であるかどうかを質問する必要がある場合は、常にUserクラスに依存すると仮定するのは公平だと思いますそれはあなたが取り除くことができない依存関係です。しかし、ユーザーを別のオブジェクトに渡して質問する必要がある場合、ユーザーに既にあるオブジェクトの上にそのオブジェクトへの新しい依存関係が作成されます。質問が頻繁に聞かれる場合、それは余分な依存関係を作成する多くの場所であり、依存関係のいずれかがそれを要求する場合、変更する必要がある多くの場所です。

これを、依存関係をUserクラスに移動することと比較してください。これで、突然、クライアントコード(質問をする必要があるコードはこのユーザーadminです)が、この質問への回答方法の実装と連動していないシステムができました。許可システムは完全に自由に変更できます。変更するには、1つのクラスの1つのメソッドのみを更新する必要があります。すべてのクライアントコードは同じままです。

isAdminパーミッションサブシステムのUserクラスに依存関係を作成することを恐れて、Userにメソッドを持たないことを主張することは、1ドルをかけて1ドルを稼ぐことに似ています。確かに、Userクラスでは1つの依存関係を回避しますが、質問をする必要があるすべての場所で1つの依存関係を作成するというコストがかかります。お買い得ではありません。


2
- 「SRPは、ちょうどオブジェクトが単一の責任だ内に入らないものの協力者に委譲しなければならないことを意味し、」偽を。SRPの定義には、オブジェクトが直接行うすべてのこと、それが委任するすべてのことが含まれます。1つのタスクのみを直接実行するが、委任を介して間接的に50の他のタスクを実行するクラスは、依然として(おそらく)SRPに違反しています。
アーロンノート

KaptajnKold:私はあなたに同意し、それについて少し罪悪感を感じるので、+ 1しました。投稿はディスカッションに追加されますが、質問には答えません。
グレンペターソン

あなたは絶対に私と一緒に同意について罪悪感を感じるべきではありません:):@GlenPetersonまあ、私はまた、「それが行われ、 『右』のように見えるもの」だった問題の一部に対処しようとした
KaptajnKold

1
@JamesSnellたぶん。もしそうなら。しかし、それは実装の詳細であり、ユーザーのisAdminメソッド内に限定します。そうすれば、ユーザーの「管理者」がブール値フィールドからより高度なものに進化しても、クライアントコードを変更する必要はありません。ユーザーが管理者であるかどうかを知る必要がある多くの場所があり、承認システムが変更されるたびにそれらを変更する必要はありません。
KaptajnKold

1
@JamesSnellたぶん私たちはお互いを誤解していますか?質問ユーザーが管理者であるかどうかは、の問題と同じではありません、ユーザーが特定のアクションを実行することが許可されているかどうか。最初の質問に対する答えは、常に文脈から独立しています。2番目の答えは、コンテキストに大きく依存します。これは、元の答えの後半で対処しようとしたものです。
KaptajnKold

1

この議論は、Eric Lippertのブログ投稿を思い起こさせました。これは、クラスの設計、セキュリティ、および正確さについての同様の議論の中で注目されました。

フレームワーククラスの多くが封印されているのはなぜですか?

特に、エリックはポイントを上げます:

4)安全。ポリモーフィズムのポイントは、動物のように見えるが実際はキリンであるオブジェクトを渡すことができるということです。ここには潜在的なセキュリティ問題があります。

封印されていない型のインスタンスを取るメソッドを実装するたびに、その型の潜在的に敵意のあるインスタンスに直面して堅牢になるようにそのメソッドを記述しなければなりません。悪意のあるWebページは実装をサブクラス化し、仮想メソッドをオーバーライドしてロジックを台無しにするものを実行し、それを渡すため、YOUR実装に当てはまることがわかっている不変条件に依存することはできません。クラスをシールするたびに、そのクラスが何をするかを知っているという自信を持って、そのクラスを使用するメソッドを書くことができます。

これは接線のように思えるかもしれませんが、SOLID 単一責任原則について他のポスターが提起したポイントと一致すると思います。User.IsAdminメソッドまたはプロパティを実装しない理由として、次の悪意のあるクラスを考慮してください。

public class MyUser : User
{

    public new boolean IsAdmin()
    {
        // You know it!
        return true;
    }

    // Anything else we can break today?

}

確かに、これは少しのストレッチです。IsAmdmin仮想メソッドの作成を提案する人はまだいませんが、ユーザー/ロールアーキテクチャが奇妙に複雑になった場合に起こる可能性があります。(またはそうではないかもしれません。public class Admin : User { ... }そのようなクラスには上記のコードが含まれている可能性があります。)悪意のあるバイナリを所定の場所に配置することは一般的な攻撃ベクトルではなく、不明瞭なユーザーライブラリよりも混乱の可能性がはるかに高くなります。特権エスカレーションのバグである可能性があります。最後に、悪意のあるバイナリまたはオブジェクトのインスタンスがランタイムに到達した場合、「特権またはセキュリティシステム」が同様の方法で置き換えられることを想像するのはそれほど簡単ではありません。

しかし、エリックの心を捉えて、特定の種類の脆弱なシステムにユーザーコードを配置すると、ゲームに負けただけかもしれません。

ああ、記録のために正確に言うと、質問の仮定に同意します。「ユーザーは、それが管理者であるかどうかを決定すべきではありません。システムUser.IsAdmin上でコードを実行している場合、コードを100%制御できないままにする方法は、悪い方法ですPermissions.IsAdmin(User user)。代わりに行う必要があります。


え?これはどうですか?セキュリティポリシーをどこに配置しても、常に安全でないものでサブクラス化する可能性があります。その何かがユーザー、プリンシパル、ポリシー、PermissionSet、その他のいずれであっても問題ありません。これはまったく関係のない問題です。
アーロンノート

これは、単一の責任を支持するセキュリティ上の議論です。あなたの主張に直接答えるために、セキュリティと許可のモジュールは封印されたクラスになるだろうが、特定の設計ではUserクラスが仮想で継承されることを望むかもしれない。これはブログ記事の最後のポイントです(おそらく、最も可能性が低い/重要なのでしょうか?)特定のクラス/オブジェクトはより安全です。
パトリックM

なぜそう言うのか分かりません。多くのセキュリティおよび許可フレームワークは非常に拡張可能です。セキュリティに関連するコア.NETタイプのほとんど(IPrincipal、IIdentity、ClaimSetなど)は、シールされているだけでなく、実際にはインターフェイスまたは抽象クラスであるため、必要なものをプラグインできます。エリックが話しているのは、System.Stringあらゆる種類の重要なフレームワークのコードがそれがどのように機能するかについて非常に具体的な仮定を立てているため、継承できるようなものは望ましくないということです。実際には、ほとんどの「ユーザーコード」(セキュリティを含む)は、テストダブルを許可するために継承可能です。
アーロンノート

1
とにかく、ポリモーフィズムは質問のどこにも言及されておらず、元のコメントが作成された場所への著者のリンクをたどると、それが継承またはクラス不変式全般を指していないことは明らかです-それは責任についてでした。
アーロンノート

私はそれが言及されなかったことを知っています、しかし、クラス責任の原則は多型に直接関連しています。IsAdminオーバーライド/選択する方法がない場合、潜在的なセキュリティホールはありません。これらのシステムのインタフェースの方法を見直し、IPrincipalそしてIIdentity、それはデザイナーが私に反対することは明らかだ、と私はポイントを認めます。
パトリックM

0

ここでの問題は次のとおりです。

if (user.isAdmin()) {
   doPriviledgedOp();
} else {
   // maybe we can anyway!
   doPriviledgedOp();
}

セキュリティを適切に設定している場合、特権メソッドは呼び出し元に十分な権限があるかどうかをチェックする必要があります。この場合、チェックは不要です。または、セキュリティに関する独自の決定を下すために、権限のないクラスを信頼していない。


4
非特権クラスとは何ですか?
ブランドン

1
この種のコードの作成を防ぐためにできることは何もありません。アプリをどのように設計しても、どこかでこのような明示的なチェックが行われ、だれかが安全でないと書いてしまう可能性があります。パーミッションシステムがロールまたはパーミッション属性でメソッドを装飾するのと同じくらい合理化されていても-誰かが誤って「public」または「everyone」パーミッションをスローする可能性があります。だから、これがUser.IsAdmin 具体的に問題のようなメソッドをどのように作るかは本当にわかりません。
アーロンノート
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.