アクセス制御が必要なアプリケーションに取り組んでいます。基本的に、私が直面している問題はこれです(非常に単純化されています)。
アプリケーションには2つの主要セクションがあります。
File[]
Contact[]
File
リソースには、多くの連絡先を割り当てることができます。逆に、Contact
リソースは多くのファイルに割り当てることができます。
私がやりたいことは、3つの役割を作成することです。
店員:
create
、read
、およびupdate
権限があり、スコープはFilesセクションです。- Contactsセクションにアクセスできません(つまり、
create
、read
、update
、またはdestroy
)
連絡先マネージャー:
create
、read
、update
、およびdestroy
権限を持ち、Contacts セクション- Filesセクションへのアクセス権がありません(つまり、
create
、read
、update
、またはdestroy
)
管理者:
create
、read
、update
、destroy
の権限があり、スコープがFilesおよびContactsセクション。
3番目の役割(管理者)については、競合はありません。最初の問題は、連絡先管理者がファイルリソースにリンクされている連絡先リソース(連絡先管理者として、彼/彼女がアクセスできない)を破棄したい場合に発生します。
さらに、ロールをさらに一歩進めて、たとえば、Filesに対して特定のCRUD
権限を付与しますContactsとして、ただし、Files内およびContact(たとえば、タイプXのファイルとタイプYの連絡先に権限が適用されます)。
次に、他の問題が発生し始めます。特定の役割が連絡先を破棄した場合、その役割がアクセスできないファイルにリンクされていますか?役割がファイルのサブセットと連絡先のサブセットにアクセスできるが、役割がアクセスできるファイルの1つに、役割がアクセスできない連絡先がリンクされている場合はどうなりますか?
RBACモデルを使用してこれを解決するエレガントな方法はありますか?私もARBACを調べましたが、比較的単純なアプリケーションではやり過ぎのようです。私には、すべての問題の根本はファイルと連絡先の多対多の関係にあるようです。
このような状況に対処する特定の方法はありますか?私はこれにかなり慣れていないので、これらの許可はこのプロジェクトの私の膝に着陸したばかりです。私はいくつかのアクセス制御モデル( OrBAC も含む)を調査しましたが、この問題に対処できるようには見えません。
正しい方向へのヘルプやヒントをいただければ幸いです。
データモデルはグラフのようになります。 Contact --- --- Fileに割り当てられ、その逆も同様です。つまりassignmentsはグラフのリンク(エッジ)です。
単一のファイルに割り当てられた複数の連絡先、または連絡先に割り当てられた複数のファイルも存在する可能性があると想定しています。別の連絡先に割り当てられているファイルに割り当てられている連絡先の削除をどのように処理しますか?リンクされたファイルを削除する連絡先を削除すると、他の連絡先が「ハング」したままになります。
assignments、つまりリンク(エッジ)を、create
、destroy
、update
権限を持つスコープとしても扱うことをお勧めします。割り当てへのアクセス許可もロールに付与します。
連絡先またはファイルを破棄するには、他のファイルまたは連絡先へのリンク(割り当て)がないことを確認する必要があります。これにより、上記の「ハング」状態が回避されます。したがって、ノードにエッジがない場合にのみ、ノードを破棄できます。
ユーザーが他のオブジェクトへのリンクを持つオブジェクトをdestroy
しようとすると、「他のファイルに割り当てられている連絡先を削除できません。最初に割り当てを削除してください」などのエラーがスローされます。
これで、assignmentスコープのCRUD権限をClerkおよびContactに割り当てることができますマネージャーロール。 Contact Managerがcontactにfileが割り当てられた状態で削除しようとすると、最初にdestroy
assignmentが必要です(destroy
権限があるため)。 fileassignmentsへのすべてのcontactがdestroyed
になると、-contactはdestroyed
。 filesを削除する責任は、とにかくClerkにありますcontactがなければ削除できます割り当てられます。
Discretionary Access Control(DAC)があなたの要件に最も適しているように思えます。まず、アクセス制御ポリシーを、アプリケーションのソースコードではなく構成で維持する価値があります-アクティビティへのコーディング。たとえば、次の代わりに(OWASP Top 10 Proactive Controls Projectの例に基づく):
if (user.hasRole("ADMIN")) || (user.hasRole("MANAGER))
deleteContact();
代わりに以下を検討してください。
if (user.hasAccess("CONTACT_DELETE"))
deleteContact();
データベースでは、各ロールに割り当てるアクティビティ権限を構成します。
データベーステーブルまたはエンティティの関係に関して:
security_activity
テーブルには、機能アクティビティごとに1つのレコードが含まれます。security_activity
は0以上に割り当てられますsecurity_role
、リンクテーブルを使用。security_role
は0以上に割り当てられますsecurity_user
、リンクテーブルを使用。上記を3つのシナリオに適用してみましょう。
店員:
- security_activity:id = 1; name = "FILE_CREATE"
- security_activity:id = 2; name = "FILE_READ"
- security_activity:id = 3; name = "FILE_UPDATE"
- security_activity:id = 4; name = "FILE_DELETE"
- security_role:id = 1; name = "書記"
- security_role_activity:id = 1; role = 1; activity = 1
- security_role_activity:id = 2; role = 1; activity = 2
- security_role_activity:id = 3; role = 1; activity = 3
- security_role_activity:id = 4; role = 1; activity = 4
- security_user:id = 1; name = "Andrew A."; job_title = "事務員"
- security_user_role:id = 1; user = 1; role = 1
Contact Manager:
- security_activity:id = 5; name = "CONTACT_CREATE"
- security_activity:id = 6; name = "CONTACT_READ"
- security_activity:id = 7; name = "CONTACT_UPDATE"
- security_activity:id = 8; name = "CONTACT_DELETE"
- security_role:id = 2; name = "Contact Manager"
- security_role_activity:id = 5; role = 2; activity = 5
- security_role_activity:id = 6; role = 2; activity = 6
- security_role_activity:id = 7; role = 2; activity = 7
- security_role_activity:id = 8; role = 2; activity = 8
- security_user:id = 2; name = "バリーB."; job_title = "連絡先マネージャー"
- security_user_role:id = 2; user = 2; role = 2
管理者:
- security_role:id = 3; name = "Admin"
- security_role_activity:id = 9; role = 3; activity = 1
- security_role_activity:id = 10; role = 3; activity = 2
- security_role_activity:id = 11; role = 3; activity = 3
- security_role_activity:id = 12; role = 3; activity = 4
- security_role_activity:id = 13; role = 3; activity = 5
- security_role_activity:id = 14; role = 3; activity = 6
- security_role_activity:id = 15; role = 3; activity = 7
- security_role_activity:id = 16; role = 3; activity = 8
- security_user:id = 3; name = "キャサリンC."; job_title = "管理"
- security_user_role:id = 3; user = 3; role = 3
「さらに、ロールをさらに一歩進めて、たとえば、ファイルと連絡先に特定のCRUD権限を与えますが、ファイル内と連絡先内にスコープがあります(たとえば、タイプXのファイルに権限が適用されます。およびタイプYのコンタクト)。」
これを実現するために、たとえばタイプXファイル用に追加のアクティビティレコードを作成できます。
if ((user.hasAccess("FILE_DELETE")) && (user.hasAccess("FILE_TYPE_X")))
deleteFile();
タイプYの連絡先の場合(これらの追加のアクティビティを役割に割り当てることを忘れないでください):
if ((user.hasAccess("CONTACT_DELETE")) && (user.hasAccess("CONTACT_TYPE_Y")))
deleteContact();
「その後、他の問題が発生します。特定の役割が、役割がアクセスできないファイルにリンクされている連絡先を破棄するとどうなりますか?役割がファイルのサブセットと連絡先のサブセットにアクセスできる場合はどうなりますか。役割がアクセスできるファイルの1つ、役割がアクセスできない連絡先がリンクされていますか?」
これを解決するには、ファイルまたは連絡先の削除を許可する前に、追加のカスタムロジックが必要になります。実装を開始する前に、疑似コードとして検討することをお勧めします。
function deleteFile($iFileId) {
/* Check permissions */
if (!user.hasAccess("FILE_DELETE")) return false;
if (!user.hasAccess("FILE_TYPE_X")) return false;
/* Prevent deletion of file if there are contacts linked /*
$aContacts = (int)DB::GetValue(sprintf("SELECT COUNT(*) FROM business_contact WHERE file=%s;",
(int)$iFileId));
if ($iContacts > 0) return false;
/* Mark file as deleted and hide throughout application */
DB::Exec(sprintf("UPDATE business_file SET del=1 WHERE id=%s;", (int)$iFileId));
/* Mark linked contacts as removed links and hide throughout application */
DB::Exec(sprintf("UPDATE business_file_contact SET del=1 WHERE file=%s;", (int)$iContactId));
}
function deleteContact(iContactId) {
/* Check permissions */
if (!user.hasAccess("CONTACT_DELETE")) return false;
if (!user.hasAccess("CONTACT_TYPE_Y")) return false;
/* Prevent deletion if linked to file */
$iLinks = (int)DB::GetValue(sprintf(
"SELECT COUNT(*) FROM business_file_contact WHERE contact=%s;", (int)$iContactId));
if ($iLinks > 0) return false;
/* Mark contact as deleted and hide throughout application */
DB::Exec(sprintf("UPDATE business_contact SET del=1 WHERE id=%s;", (int)$iContactId));
}
「RBACモデルを使用してこれを解決するためのエレガントな方法はありますか?私もARBACを調べましたが、比較的単純なアプリケーションではやり過ぎのようです。私にとって、すべての問題の根本はファイルと連絡先の間の多くの関係。このような状況に対処するための具体的な方法はありますか?私はこれにかなり慣れていません。これらの権限はこのプロジェクトの膝に着陸したばかりです。いくつかのアクセス制御モデル( OrBAC)でさえ、この問題に対処することはできないようです。正しい方向への助けやヒントがあれば、大歓迎です。」
上記の例では、ほとんどの方法を使用できます。データベース構造に多対多の関係があることはごく普通のことです。これらは通常、リンクテーブルを使用して管理されます。正規化およびエンティティ関係図の主題について読んでください。
ユーザーがアクセスできるレコードに関する制御をさらに追加する必要がある場合は、hasAccess同等の関数を変更して、レコードIDを2番目のパラメーターとして受け入れ、hasAccess関数で必要なロジックを適用して、構成されたセキュリティポリシーに基づいてデータベース。
if (user.hasAccess("CONTACT_DELETE", 37991))
deleteAccount();
レコードのアクセスがデフォルトで制限される場合は、アクセス権を持つユーザーのホワイトリストを保持するbusiness_contactまたはbusiness_fileテーブルに列を作成できます。ファイルがフォルダーやサブフォルダーなどにある場合は、おそらくフォルダーレコードにこの列があるはずです。この列のアスタリスクは、「すべて許可」と解釈できます。少なくともこのリストに作成者のユーザーIDを含めることを忘れないでください!
これは1か月前に書いたもので、私は戦いに遅れています。しかし、あなたが説明しているものは、「属性ベースのアクセス制御」がすべて書かれています。 abac は、保護するアプリケーション/ APIから認証を外部化/分離するのに役立ちます。これは、認証ロジックとは関係なく機能を開発できることを意味します。
XACMLと [〜#〜] alfa [〜#〜] (承認の略語)という標準がいくつかあります。
これはアーキテクチャがどのように見えるかです:
以前に与えられた回答には、カスタムコードまたは重いロールエンジニアリング、あるいはその両方が必要です。 ALFAでは、その必要はありません。興味のある属性を使用する単純な古い英語のポリシーを作成するだけです。次に例を示します。