1. 序章

この記事では、さまざまなアクセス制御モデルを実際に実装する方法について説明します。

2. アクセス制御モデルとは何ですか?

アプリケーション、特にWebベースのアプリケーションの一般的な要件は、ポリシーとも呼ばれる特定の条件のセットが満たされた場合にのみ、一部のアクションを実行できることです。 わかりました、これは非常に一般的な要件なので、いくつかの例を示しましょう。

  • インターネットフォーラム:メンバーのみが新しいメッセージを投稿したり、既存のメッセージに返信したりできます
  • Eコマースサイト:通常のユーザーは自分の注文のみを表示できます
  • 銀行のバックオフィス:アカウントマネージャーは、自分のクライアントのポートフォリオを管理できます。 それらのポートフォリオに加えて、彼/彼女はまた、彼/彼女が一時的に不在(例えば、休暇)であり、前者がそのピアとして機能するときに、別のアカウントマネージャーのクライアントのポートフォリオを管理することができます。
  • デジタルウォレット:ユーザーのタイムゾーンでの支払いは20:00から08:00まで$500に制限されています

特定のアプリケーションに採用するアクセス制御モデルは、着信要求を評価し、要求を続行できるかどうかを決定する責任があります。 後者の場合、結果は通常、ユーザーに返送されるエラーメッセージになります。

明らかに、これらの例のそれぞれは、特定の要求を承認するときに異なるアプローチを必要とします。

3. アクセス制御モデルタイプ

前の例から、許可/拒否の決定を行うには、要求に関連するさまざまな側面を考慮する必要があることがわかります。

  • リクエストに関連付けられたID。 ここでは、匿名アクセスでさえIDの形式を持っていることに注意してください
  • リクエストの対象となるオブジェクト/リソース
  • それらのオブジェクト/リソースに対して実行されるアクション
  • リクエストに関するコンテキスト情報。 使用される時刻、タイムゾーン、および認証方法は、この種のコンテキスト情報の例です。

アクセス制御モデルは、次の3つのタイプに分類できます。

  • ロールベースのアクセス制御(RBAC)
  • アクセス制御リスト(ACL)
  • 属性ベースのアクセス制御(ABAC)

タイプに関係なく、通常、モデル内の次のエンティティを識別できます。

  • PEP、またはポリシー施行ポイント PDP によって返された結果に基づいて、リクエストをインターセプトし、続行するかどうかを決定します。
  • PDP、またはポリシー決定ポイント:ポリシーを使用して要求を評価し、アクセス決定を生成します
  • PIP、またはポリシー情報ポイント:PDPがアクセス決定を行うために使用する情報へのアクセスを保存および/または仲介します。
  • PAP、またはポリシー管理ポイント:アクセスの意思決定に関連するポリシーおよびその他の運用面を管理します。

次の図は、これらのエンティティが互いに論理的にどのように関連しているかを示しています。

自律エンティティとして描かれていますが、実際には、一部またはすべてのモデル要素がアプリケーション自体に埋め込まれていることに注意することが重要です

また、このモデルでは、ユーザーのIDを確立する方法については説明していません。 それでも、リクエストの続行を許可するかどうかを決定する際には、この側面を考慮することができます。

ここで、この汎用アーキテクチャを上記の各モデルに適用する方法を見てみましょう。

4. ロールベースのアクセス制御

このモデルでは、PDP決定プロセスは2つのステップで構成されています。

  • まず、着信要求のIDに関連付けられたロールを回復します。
  • 次に、それらの役割をリクエストポリシーと一致させようとします

このモデルの具体的な実装は、@HttpConstraintアノテーションとそれに相当するXMLの形式でJavaEE仕様に含まれています。 これは、サーブレットに適用される場合の注釈の一般的な使用法です。

@WebServlet(name="rbac", urlPatterns = {"/protected"})
@DeclareRoles("USER")
@ServletSecurity(
  @HttpConstraint(rolesAllowed = "USER")
)
public class RBACController  extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("Hello, USER");
    }
}

Tomcatサーバーの場合、前述のアクセス制御モデルエンティティを次のように識別できます。

  • PEP:ターゲットサーブレットにこのアノテーションが存在するかどうかをチェックし、関連付けられたレルムを呼び出して現在のリクエストに関連付けられたIDを回復するセキュリティ Valve
  • PDP:特定のリクエストに適用する制限を決定するRealm実装
  • PIP:セキュリティ関連の情報を格納する特定のレルム実装によって使用されるバックエンド。 RBACモデルの場合、重要な情報はユーザーのロールセットであり、通常はLDAPリポジトリから取得されます。
  • ポリシーストア:この場合、アノテーションはストア自体です
  • PAP:Tomcatは動的なポリシー変更をサポートしていないため、実際に変更する必要はありません。 ただし、想像力を働かせれば、注釈を追加したり、アプリケーションのWEB-INF/web.xmlファイルを編集したりするために使用される任意のツールでそれを識別できます。

他のセキュリティフレームワーク(Spring Securityなど)も同様に機能します。 ここで重要な点は、特定のフレームワークが一般的なモデルに正確に準拠していなくても、そのエンティティは多少偽装されていても、そこに存在するということです。

4.1. 役割の定義

正確には何が役割を構成しますか? 実際には、ロールは、ユーザーが特定のアプリケーションで実行できる関連アクションの名前付きセットです。 これらは、アプリケーションの要件に応じて、必要に応じて大まかにまたは細かく定義できます。

それらの粒度レベルに関係なく、それらを定義することは良い習慣です。そのため、それぞれが互いに素な機能のセットにマップされます。 このように、副作用を恐れることなく役割を追加/削除することで、ユーザープロファイルを簡単に管理できます。

ユーザーと役割の関連付けについては、直接または間接的なアプローチを使用できます。 前者では、ユーザーに直接役割を割り当てます。 後者には、役割を割り当てる中間エンティティ(通常はユーザーグループ)があります。

この関連付けの仲介エンティティとしてグループを使用する利点は、一度に多くのユーザーに役割を簡単に再割り当てできることです。この側面は、人々が常に1つの組織から移動している大規模な組織のコンテキストに非常に関連しています。別のエリアへ。

同様に、間接モデルでは、通常はアプリケーションをリファクタリングした後、既存のロール定義を簡単に変更することもできます。

5. アクセス制御リスト

ACLベースのセキュリティ制御により、個々のドメインオブジェクトにアクセス制限を定義できます。これは、制限が通常オブジェクトのカテゴリ全体に適用されるRBACとは対照的です。 上記のフォーラムの例では、RBACのみのアプローチを使用して、新しい投稿を読み取って作成できることを定義できます。

ただし、ユーザーが自分の投稿を編集できる新しい機能を作成することにした場合、RBACだけでは十分ではありません。 この場合、意思決定エンジンは、誰だけでなく、どの投稿が編集アクションのターゲットであるかを考慮する必要があります。

この簡単な例では、データベースに1つの author 列を追加し、それを使用して編集アクションへのアクセスを許可または拒否できます。 しかし、協調編集をサポートしたい場合はどうでしょうか。 この場合、投稿を編集できるすべての人のリスト(ACL)を保存する必要があります。

ACLの処理には、いくつかの実際的な問題があります。

  • ACLはどこに保存しますか?
  • ラージオブジェクトコレクションを取得するときにACL制限を効率的に適用するにはどうすればよいですか?

SpringSecurityACLライブラリはACLライブラリの良い例です。 専用のデータベーススキーマとキャッシュを使用してACLを実装し、SpringSecurityと緊密に統合されています。 これは、このライブラリに関する記事を基にした短い例で、オブジェクトレベルでアクセス制御を実装する方法を示しています。

@PreAuthorize("hasPermission(#postMessage, 'WRITE')")
PostMessage save(@Param("noticeMessage")PostMessage postMessage);

ACLのもう1つの良い例は、オブジェクトを保護するためにWindowsが使用するアクセス許可システムです。 すべてのセキュリティ保護可能なオブジェクト(ファイル、ディレクトリ、プロセスなど)には、個々のユーザー/グループと関連する権限のリストを含むセキュリティ記述子が添付されています。

Windows ACLは非常に強力であり(または、誰に尋ねるかによっては複雑になります)、管理者は個々のユーザーやグループにアクセス許可を割り当てることができます。 さらに、個々のエントリは、可能なアクションごとに許可/拒否のアクセス許可を定義します。

6. 属性ベースのアクセス制御

属性ベースの制御モデルにより、ID、アクション、およびターゲットオブジェクトだけでなく、要求に関連するコンテキスト情報にも基づいたアクセス決定が可能になります

XACML 標準は、おそらくこのモデルの最もよく知られた例であり、XMLドキュメントを使用してアクセスポリシーを記述します。 これは、この標準を使用してデジタルウォレットの引き出しルールを説明する方法です。

<Policy xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" 
  PolicyId="urn:baeldung:atm:WithdrawalPolicy"
  Version="1.0" 
  RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:deny-overrides">
    <Target/>
    <Rule RuleId="urn:oasis:names:tc:baeldung:WithDrawalPolicy:Rule1" Effect="Deny">
        <Target>
            <AnyOf>
                <AllOf>
... match rule for the withdrawal action omitted
                </AllOf>
            </AnyOf>
        </Target>
        <Condition>
... time-of-day and amount conditions definitions omitted
        </Condition>
    </Rule>
</Policy>

完全なルール定義はオンラインで利用できます。

その冗長性にもかかわらず、その一般的な構造を理解することは難しくありません。 ポリシーには、評価時に効果:許可または拒否が発生する1つ以上のルールが含まれています。

各ルールには、リクエストの属性を使用して論理式を定義するターゲットが含まれています。 オプションで、ルールには、その適用性を定義する1つ以上のCondition要素を含めることもできます。

実行時に、XACMLベースのアクセス制御PEPは RequestContext インスタンスを作成し、評価のためにそれをPDPに送信します。 次に、エンジンは適用可能なすべてのルールを評価し、アクセス決定を返します。

このRequestContextに存在する情報の種類は、このモデルを前のモデルと区別する主な側面です。 たとえば、デジタルウォレットアプリケーションでの引き出しを承認するために構築されたリクエストコンテキストのXML表現を見てみましょう。

<Request 
    xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
    CombinedDecision="true"
    ReturnPolicyIdList="false">
    
    <Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action">
... action attributes omitted
    </Attributes>
    <Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment">
... environment attributes (e.g., current time) omitted
    </Attributes>
    <Attributes Category="urn:baeldung:atm:withdrawal">
... withdrawal attributes omitted 
    </Attributes>
</Request>

21:00にこのリクエストをXAMLルール評価エンジンに送信すると、夜間のトランザクションの最大許容量を超えているため、期待される結果はこの撤回の拒否になります。

ABACモデルの主な利点は、その柔軟性です。ポリシーを変更するだけで、複雑なルールを定義でき、さらに重要なことに、変更できます。 実装によっては、リアルタイムで実行することもできます。

6.1. XACML4J

XACML4J は、Java用のXACML3.0標準のオープンソース実装です。 これは、ABACモデルに必要な評価エンジンと関連エンティティの実装を提供します。 そのコアAPIはPolicyDecisionPointインターフェイスであり、当然のことながら、PDPロジックを実装しています。

PDPを作成したら、それを使用するには2つの手順が必要です。 まず、 RequestContext を作成して、評価するリクエストに関する情報を入力します。

... attribute categories creation omitted
RequestContext request = RequestContext.builder()
  .attributes(actionCategory,environmentCategory,atmTxCategory)
  .build();

ここで、各 xxxCategory パラメーターには、関連付けられたCategoryの属性のセットが含まれています。 フルコードは、利用可能なビルダーを使用して、21:00に発生する$1,200.00の引き出しのテストリクエストを作成します。 または、JAXB互換のソースから直接RequestContextオブジェクトを作成することもできます。

次に、このオブジェクトを PolicyDecisionPointサービスのdecide()メソッドに渡して評価します。

ResponseContext response = pdp.decide(request);
assertTrue(response.getDecision() == Decision.DENY); 

返されたResponseContextには、ポリシー評価結果を含むDecisionオブジェクトが含まれています。 さらに、診断情報および追加の義務および/またはアドバイスをPEPに返す場合もあります。 義務とアドバイスはそれ自体がトピックであるため、ここでは取り上げません。 このAxiomaticのチュートリアルは、この機能を使用して、一般的な記録システムアプリケーションに規制管理を実装する方法を示しています。

6.2. XACMLなしのABAC

XACMLの複雑さにより、通常、ほとんどのアプリケーションではやり過ぎになります。ただし、アプリケーションで基盤となるモデルを使用することはできます。 結局のところ、特定のユースケースに合わせたより単純なバージョンをいつでも実装できます。おそらく、いくつかのパラメーターを外部化するだけですよね?

まあ、ベテランの開発者なら誰でもこれがどのように終わるか知っています…

ABAC実装のトリッキーな側面は、リクエストのペイロードから属性を抽出する方法です。 サーブレットフィルターやJAX-RSインターセプターなど、リクエストを処理する前にカスタムロジックを挿入する標準的なメソッドは、生のペイロードデータにのみアクセスできます。

最近のアプリケーションはJSONまたは同様の表現を使用する傾向があるため、PEPはペイロード属性を抽出する前にそれをデコードする必要があります。 これは、特に大きなペイロードの場合、CPUとメモリの使用量に潜在的な打撃を与えることを意味します。

この場合、より良いアプローチは、AOPを使用してPEPを実装することです。 この場合、アスペクトハンドラコードは、デコードされたバージョンのペイロードにアクセスできます。

7. 結論

この記事では、さまざまなアクセス制御モデルと、アプリケーションがそれらを使用してアクセスルールを適用する方法について説明しました。

いつものように、例の完全なソースコードはGitHubにあります。