【PL/SQL】Invoker RightsとDefiner Rightsを使い切る完全ガイド|判断フロー・内部動作・INHERIT PRIVILEGES・名前解決の罠

【PL/SQL】Invoker RightsとDefiner Rightsの違いと使い分け PL/SQL

PL/SQLのプロシージャやパッケージは、「どのユーザーの権限で実行されるか」をAUTHID句で指定できます。デフォルトのDefiner Rights(定義者権限)作成者の権限で実行され、Invoker Rights(呼び出し者権限)呼び出したユーザーの権限で実行されます。シンプルな違いに見えますが、選択を誤ると「権限不足エラー」「想定外の権限昇格」「ロールが効かない」といった事故に直結します。

多くの解説では「定義者権限はカプセル化、呼び出し者権限はライブラリ向け」のような大雑把な説明で終わりますが、実装現場で本当に欲しいのは「自分の関数はどちらにすべきか」を即決できる判断基準です。加えて12c以降のINHERIT PRIVILEGESBEQUEATH句といった重要な拡張を理解しないと近代的な設計はできません。

この記事ではAUTHID選択の判断フローを中心に、内部の権限解決メカニズム、INHERIT PRIVILEGES、ビュー・トリガーでの動作差、名前解決の罠、切り替え時の注意点、アンチパターン6選、FAQまで2026年版で整理します。権限設計の全体像(スキーマ分離・GRANT戦略)を学びたい場合は権限分離とセキュリティパッケージを、AUTHIDのベストプラクティスはAUTHID設計のベストプラクティスを併せてご覧ください。

この記事でわかること

  • Definer Rights/Invoker Rightsの内部動作と権限解決のタイミング
  • 「迷ったらどっちか」を即決できる判断フローチャート
  • ロールがDefinerでは効かないという最重要ルール
  • Definer Rightsの典型ユースケース(API公開・カプセル化)
  • Invoker Rightsの典型ユースケース(ライブラリ・マルチテナント)
  • 12c以降のINHERIT PRIVILEGES/BEQUEATH句の使い方
  • 名前解決の罠(シノニム・ビュー・スキーマ修飾)と回避策
  • パッケージ・トリガー・ビューでのAUTHID挙動の差
  • Definer→Invokerへの安全な切り替え手順
  • 本番で踏むアンチパターン6選
スポンサーリンク

30秒でわかるAUTHID選択の結論

忙しい読者向けの結論先出しです。

結論 理由・効果
① 業務APIならDefiner Rights(デフォルト) 呼出し元に表権限を渡さずAPIだけ公開できる
② ユーティリティならInvoker Rights 呼出し者の権限と可視性を尊重しライブラリ的に使える
ロールはDefinerで無効化される 必要な表権限はロール経由ではなく直接GRANTする
④ Invoker Rightsで使うパッケージは名前解決が呼出し者基準 シノニム・ビューが想定外の表に解決される事故防止に明示的修飾を
⑤ 12c以降はINHERIT PRIVILEGESで権限昇格を制御 呼出し者がdefinerに不当に昇格する攻撃を防げる
⑥ ビューのBEQUEATHもAUTHIDと同じ概念 BEQUEATH DEFINER/CURRENT_USERでビューの権限解釈を制御
切り替えはテスト必須 Definer↔Invokerの切替は権限と名前解決の両方を変える

権限解決の内部動作|どのタイミングで何が起きるか

AUTHIDは「誰の権限で実行するか」を決めるだけでなく、名前解決(テーブル名がどのスキーマを指すか)にも影響します。両者を区別して理解することが本質です。

Definer Rights(AUTHID DEFINER)

関数を作成したスキーマ(DEFINER)の権限と名前解決コンテキストで実行されます。SELECT * FROM employeesと書いてあればDEFINERのスキーマのemployeesを参照し、その表へのアクセス権限はDEFINER所有者を見て判定。呼び出し者がempolyeesに権限を持っていなくても実行できるのが特徴です。これは「呼び出し者を信頼してDEFINERの強い権限を貸す」モデルなのでカプセル化過剰権限の両側面があります。

Invoker Rights(AUTHID CURRENT_USER)

関数を呼び出したユーザー(CURRENT_USER)の権限と名前解決コンテキストで実行されます。同じSELECT * FROM employeesでも呼出し者のスキーマのemployeesを参照しに行き、アクセス権限も呼出し者で判定。マルチスキーマで「誰が呼ぶか」によって参照表が変わるのが特徴で、共通ライブラリ的な使い方に適します。反面、想定したテーブルが呼出し者のスキーマにないとORA-00942: table or view does not existになります。

権限解決の重要ルール|ロールはDefinerで無効

ここが最も重要なポイントです。Definer Rightsで実行されるPL/SQL内では、DEFINER所有者がロール経由で持っている権限は完全に無視されます。たとえばDEFINERがDBAロールでSELECT権限を持っていても、PL/SQL内ではその権限は使えません。必ず直接GRANTで付与した権限のみが有効です。Invoker Rightsではロールが有効になる、という違いも使い分けの判断基準になります。

Definer/Invokerでの動作差を実例で確認
-- ユーザーDATAがemployees表を所有
CREATE USER data IDENTIFIED BY ...;
GRANT CREATE TABLE TO data;
GRANT CREATE PROCEDURE TO data;

-- ユーザーAPPがpkg_empを作成(DATAの表を参照)
CREATE USER app IDENTIFIED BY ...;
GRANT CREATE PROCEDURE TO app;
GRANT SELECT ON data.employees TO app;   -- ★直接GRANTが必須

-- ユーザーCALLERがpkg_empを呼び出す
CREATE USER caller IDENTIFIED BY ...;
GRANT EXECUTE ON app.pkg_emp TO caller;
-- CALLERにはdata.employeesへの直接権限なし

-- ① Definer Rightsの場合(呼出し者に表権限不要)
CREATE OR REPLACE PACKAGE app.pkg_emp_def AUTHID DEFINER AS
  PROCEDURE list_all;
END;
/
CREATE OR REPLACE PACKAGE BODY app.pkg_emp_def AS
  PROCEDURE list_all IS
  BEGIN
    FOR rec IN (SELECT employee_id FROM data.employees) LOOP
      DBMS_OUTPUT.PUT_LINE(rec.employee_id);
    END LOOP;
  END;
END;
/
-- CALLERが呼ぶ → 成功(APPの権限で実行されるため)
CONNECT caller/...
EXEC app.pkg_emp_def.list_all;   -- OK

-- ② Invoker Rightsの場合(呼出し者に表権限必要)
CREATE OR REPLACE PACKAGE app.pkg_emp_inv AUTHID CURRENT_USER AS
  PROCEDURE list_all;
END;
/
CREATE OR REPLACE PACKAGE BODY app.pkg_emp_inv AS
  PROCEDURE list_all IS
  BEGIN
    FOR rec IN (SELECT employee_id FROM data.employees) LOOP
      DBMS_OUTPUT.PUT_LINE(rec.employee_id);
    END LOOP;
  END;
END;
/
-- CALLERが呼ぶ → 失敗(CALLERにdata.employees権限なし)
CONNECT caller/...
EXEC app.pkg_emp_inv.list_all;   -- ORA-00942

-- 解決:CALLERに直接GRANT
GRANT SELECT ON data.employees TO caller;
EXEC app.pkg_emp_inv.list_all;   -- OK

「ロールでGRANTしたのにPL/SQL内で見えない」はDefiner Rightsの最大の落とし穴です。本番リリースでは「動作確認はDBA権限で行い、実運用では権限不足で失敗」というケースが頻発します。PL/SQLが参照する表には必ず所有者から直接GRANTすることを徹底してください。

AUTHID選択の判断フロー|迷ったらこれで決める

実装時に「Definer/Invokerどちらにすべきか」を即決できる判断フローを示します。3つの質問に答えるだけで決まります。

質問1:呼び出し元に表権限を渡したくないか?

「APIだけ公開して内部の表は隠したい」「呼び出し者にSELECT/INSERT権限を直接付与したくない」のようなカプセル化要件がある場合はDefiner Rights。APIで業務操作だけを抽象化して提供できます。

質問2:呼び出し者ごとに参照する表が変わるべきか?

「ユーザーAが呼ぶとユーザーAの表、ユーザーBが呼ぶとユーザーBの表」のようなマルチテナント/ライブラリ要件がある場合はInvoker Rights。同じコードで呼出し者ごとに違う表を扱えます。

質問3:呼び出し者のロール権限を反映させたいか?

「呼出し者がREADER_ROLEならRead-only、WRITER_ROLEならRead/Write」のような動的アクセス制御が必要ならInvoker Rights。Definer RightsではPL/SQL内でロールが効かないため実現できません。

状況 選択
業務APIで呼出し者に内部表を見せたくない Definer Rights
共通ユーティリティでスキーマごとに違う表を扱う Invoker Rights
マルチテナントで呼出し者の可視性をそのまま反映 Invoker Rights
呼出し者のロール(READER/WRITER等)で挙動を切替 Invoker Rights
監査・特権操作を所有者の権限で安全に実行 Definer Rights
動的SQL(DDL等)を呼出し者の権限で実行 Invoker RightsAUTHID CURRENT_USER
迷っていてとりあえず動かす Definer Rights(デフォルト)

INHERIT PRIVILEGES(12c以降)|権限昇格を防ぐ重要機能

Oracle 12cから導入されたINHERIT PRIVILEGESは、Invoker RightsでDefinerが呼び出される際の権限昇格を制御する重要な機能です。これを理解せずに本番運用すると、権限の弱いユーザーが強い権限を持つDefinerプロシージャを通じて意図しない操作を実行できてしまうセキュリティ事故が起きます。

問題:Invoker Rights関数の中で起きる権限昇格

Invoker Rights関数はCALLERの権限で動きますが、その中で別のDefinerプロシージャを呼ぶとその瞬間からDEFINERの強い権限に切り替わります。これは便利な反面、悪意あるDEFINERが用意した関数を呼び出し者が知らずに呼ぶと権限昇格攻撃になり得ます。12c以降ではこれをブロックするセキュリティ機構が入りました。

INHERIT [ANY] PRIVILEGES の動作

呼び出し元ユーザー(CALLER)が「DEFINERの権限を借りてもよい」と明示的にGRANTしないと権限昇格が起きません。これによりDEFINERは「自分が信頼するCALLERだけが自分のDefinerを実行時に権限借用できる」設計が可能になります。

INHERIT PRIVILEGES の使い方
-- 12c以降では、Invoker Rights関数からDefiner関数を呼ぶときに
-- CALLERがDEFINERにINHERIT PRIVILEGESをGRANTしている必要がある

-- ① 通常の状態(特に何もしない)
CREATE OR REPLACE PROCEDURE strong_def_proc AUTHID DEFINER AS
BEGIN
  -- 強い権限が必要な処理
  EXECUTE IMMEDIATE 'GRANT SELECT ON sensitive_table TO public';
END;
/

-- ② Invoker Rights側からの呼び出し
CREATE OR REPLACE PROCEDURE caller_proc AUTHID CURRENT_USER AS
BEGIN
  strong_def_proc;   -- ← CALLERが信頼してINHERITしないと失敗
END;
/

-- ③ CALLERユーザーがDEFINERに権限借用を許可
CONNECT caller/...
GRANT INHERIT PRIVILEGES ON USER caller TO definer_user;

-- これでcaller_procからstrong_def_procを呼べる

-- ④ デフォルトで全員から借用権を取得(推奨されない)
GRANT INHERIT ANY PRIVILEGES TO definer_user;  -- 全ユーザーから借用OK

-- ⑤ 取り消し(権限昇格を完全に遮断)
REVOKE INHERIT PRIVILEGES ON USER caller FROM definer_user;

Oracle 12cにアップグレードした既存システムでは移行期間中の互換性のためINHERIT PRIVILEGES がデフォルトでPUBLICに付与されている場合があります。セキュリティを強化したい場合はREVOKE INHERIT PRIVILEGES ON USER ... FROM PUBLIC;を実行し、必要なペアだけに明示的にGRANTする運用に切り替えてください。

名前解決の罠|シノニム・ビューでスキーマが切り替わる

Invoker Rightsで最も事故が起きやすいのが名前解決です。コード内に書いたSELECT * FROM employeesがどのスキーマのemployeesを指すかが、AUTHIDによって変わります。シノニムやビューが絡むと特に複雑になります。

名前解決の挙動を実例で確認
-- DATA, APP, CALLER の3スキーマで、それぞれにemployees表があるとする
CREATE TABLE data.employees(...);
CREATE TABLE app.employees(...);
CREATE TABLE caller.employees(...);

-- APPがプロシージャを作成
CREATE OR REPLACE PROCEDURE app.show_emps AUTHID DEFINER AS
BEGIN
  -- 修飾なし → APP.employees を参照(DEFINERのスキーマ)
  FOR rec IN (SELECT * FROM employees) LOOP NULL; END LOOP;
END;
/

CREATE OR REPLACE PROCEDURE app.show_emps_inv AUTHID CURRENT_USER AS
BEGIN
  -- 修飾なし → CALLER.employees を参照(呼出し者のスキーマ)
  FOR rec IN (SELECT * FROM employees) LOOP NULL; END LOOP;
END;
/

CONNECT caller/...
EXEC app.show_emps;       -- → APP.employees を見る
EXEC app.show_emps_inv;   -- → CALLER.employees を見る

-- ✅ 確実に同じ表を見るには完全修飾名を使う
CREATE OR REPLACE PROCEDURE app.show_emps_safe AUTHID CURRENT_USER AS
BEGIN
  -- 完全修飾でDATA.employees を明示
  FOR rec IN (SELECT * FROM data.employees) LOOP NULL; END LOOP;
END;
/

シノニムの罠:シノニムも名前解決の対象なので、PUBLICシノニムやスキーマ別シノニムが絡むと「どの表に解決されたか」を追うのが困難になります。Invoker Rightsで信頼性が必要な処理では必ず完全修飾名(owner.table)を使うのが安全策。デバッグ困難なバグを未然に防げます。

ビュー・トリガーでの特殊事情

AUTHIDはプロシージャ/関数/パッケージだけの概念ではなく、ビューやトリガーにも類似の機構があります。個別の挙動を押さえておかないと「同じ感覚で書いたのに動作が違う」事故が起きます。

ビューの BEQUEATH 句(12c以降)

ビューは伝統的に常にDefiner権限で評価されていましたが、12cからBEQUEATH CURRENT_USERを指定してInvoker Rights相当の動作にできるようになりました。マルチテナント環境で呼び出し者ごとに違う行を返すビューを作りたい場合に有用です。

BEQUEATH 句でビューを Invoker Rights化
-- 通常のビュー(BEQUEATH DEFINER がデフォルト)
CREATE OR REPLACE VIEW v_emp_def AS
SELECT * FROM employees;

-- BEQUEATH CURRENT_USER で呼出し者の権限・名前解決を使う
CREATE OR REPLACE VIEW v_emp_inv
  BEQUEATH CURRENT_USER AS
SELECT * FROM employees;
-- → 呼出し者のスキーマのemployeesを参照

-- 設定確認
SELECT view_name, bequeath
  FROM user_views WHERE view_name LIKE 'V_EMP%';

トリガーは常にDefiner権限

トリガーは定義者権限のみで実行されます。AUTHIDを指定することはできません。トリガー内で外部スキーマの表を更新する場合は定義者に直接GRANTが必要です。これはトリガーの本質である「テーブル変更時の自動処理」を一貫した権限で実行するための設計上の制限です。

パッケージ全体に対する単一指定

AUTHIDはパッケージSPECに書き、パッケージ内の全サブプログラムに一括適用されます。個別のプロシージャごとにDefiner/Invokerを混在できないので、混在が必要なら別パッケージに分割する設計判断が必要です。

Definer↔Invoker切り替えの安全な手順

既存のDefiner RightsをInvoker Rightsに切り替えたい(あるいはその逆)場合、権限と名前解決の両方が変わるため本番影響が読めないことが多いです。次の手順で安全に進めます。

切り替え時のチェックリスト実行スクリプト
-- 切り替え前の調査スクリプト

-- ① 対象パッケージの呼び出し元一覧
SELECT owner, name, type, referenced_owner, referenced_name
  FROM dba_dependencies
 WHERE referenced_owner = 'APP'
   AND referenced_name = 'PKG_TARGET'
 ORDER BY owner, name;

-- ② 対象パッケージが参照する表・ビュー
SELECT referenced_owner, referenced_name, referenced_type
  FROM dba_dependencies
 WHERE owner = 'APP' AND name = 'PKG_TARGET'
   AND referenced_type IN ('TABLE','VIEW','SYNONYM');

-- ③ 呼出し者候補ユーザーの権限チェック
-- (Invoker化したときに必要な権限を持っているか)
SELECT grantee, privilege, table_name, owner
  FROM dba_tab_privs
 WHERE grantee = 'CALLER_USER'
   AND owner = 'DATA';

-- ④ シノニム解決の確認(INVOKER化で名前解決が変わる影響)
SELECT owner, synonym_name, table_owner, table_name
  FROM dba_synonyms
 WHERE table_name IN ('EMPLOYEES','ORDERS','PRODUCTS');

-- 切り替え後の動作確認

-- ⑤ AUTHID変更
ALTER PACKAGE app.pkg_target COMPILE SPECIFICATION
  REUSE SETTINGS;
-- AUTHIDはSPEC編集が必要なのでCREATE OR REPLACEで書き直し

-- ⑥ 全呼び出し元から動作テストを実施
-- ⑦ 監査ログで権限不足エラー(ORA-00942/01031)を確認

-- ⑧ ロールバック準備:旧版を別名で保存しておく
-- CREATE OR REPLACE PACKAGE app.pkg_target_v1 AS ...

本番切り替えは絶対に段階的に。①ステージング環境で全呼び出し元から動作テスト、②本番では深夜帯など低負荷時間に切り替え、③切替後30分は監査ログでORA-942/ORA-1031(権限不足)を監視、④旧版にロールバックできるよう旧コードを別名で保管。権限切替の事故は復旧が難しいので慎重すぎるくらいでちょうど良いです。

本番で踏むアンチパターン6選

① ロール経由の権限を当てにしてDefiner Rightsで実装

「DBAロールを持っているから動く」と開発時に確認した実装が、本番で個別ユーザに切り替えた瞬間にORA-00942。必ず直接GRANTで必要権限を付与してください。

② Invoker RightsなのにシノニムやビューでDefinerスキーマを参照

「Invokerだから呼出し者の表を見るはず」と思っていたらPUBLICシノニムが先に解決されてDefinerの表を見ていた、というのは典型的バグ。完全修飾名で書くか、シノニムを使うならUSER_SYNONYMSで解決先を確認する習慣を。

③ 動的SQL内でロールが効くと勘違い

Definer Rightsの動的SQL(EXECUTE IMMEDIATE)でもロール権限は無効です。「動的SQLは別モードで動くはず」という誤解で権限不足エラーを踏みます。動的でも静的でも同じルールです。

④ パッケージ内で部分的にAUTHIDを変えようとする

AUTHIDはパッケージ単位で1つだけ。個別プロシージャでAUTHIDを混在させたい場合はパッケージを分割するしかありません。インラインで切り替える方法はないので、責務分割の設計判断が必要。

⑤ 12cでINHERIT PRIVILEGESを意識しない

古いシステムをアップグレードした後、INHERIT PRIVILEGESの仕組みを理解せず使い続けると気付かない権限昇格経路が残ります。本番ではPUBLICからINHERIT PRIVILEGESを必ずREVOKEし、必要なペアだけに明示的GRANTする運用に。

⑥ 切り替え前に呼び出し元を全部洗い出さない

Definer→Invoker切替で「主要な呼び出し元しか確認しなかった」結果、夜間バッチや別チームのスクリプトで権限不足エラーが頻発。DBA_DEPENDENCIESで全呼び出し元を必ず洗い出してから切り替えてください。

よくある質問

QAUTHIDを指定しないとどうなる?
AデフォルトはAUTHID DEFINERです。何も書かなければ作成者の権限と名前解決コンテキストで実行されます。明示的にDefinerにしたい場合もAUTHID DEFINERと書いておくとコードの意図が明確になり、レビュー・保守時に判断材料になります。
QDefiner Rightsでロールの権限が効かないのはなぜ?
APL/SQLの設計上、コンパイル時に権限チェックを行うためです。ロール権限は実行時に動的に切り替わる可能性があるので、コンパイル時の安全性を担保するために無効化されています。Invoker Rightsは実行時の権限解釈なのでロールが反映されます。「コンパイル時 vs 実行時」の違いと覚えると理解しやすいです。
QInvoker Rightsで呼ぶたびに権限チェックされて遅くなる?
A名前解決と権限チェックが実行ごとに走りますがオーバーヘッドはごく小さいです。カーソルキャッシュも効くので2回目以降はさらに高速化されます。実用上は性能差を理由に選択を変える必要はなく、本記事の判断フローでセキュリティ要件に基づき選んでください。
Qストアド実行時のCURRENT_USERとSESSION_USERの違いは?
ACURRENT_USER現在の権限コンテキストのユーザー、SESSION_USERログイン時のユーザーです。Definer Rightsで実行中はCURRENT_USER=DEFINER、SESSION_USER=ログインユーザー。Invoker RightsではCURRENT_USER=SESSION_USER。SYS_CONTEXT('USERENV', ...)で取得して監査・分岐に使えます。
Q関数の中で権限を一時的に切り替えたい
A関数の途中でAUTHIDを切り替えることはできません。別のAUTHID関数に処理を委譲することで実現します。「ほとんどはInvokerで動かしたいが、一部だけ強い権限が必要」なら、その強い権限部分をDefiner Rightsの別パッケージに切り出してINHERIT PRIVILEGESで安全に呼び出す設計が定石です。
QPRAGMA AUTONOMOUS_TRANSACTIONとAUTHIDは併用できる?
A可能で互いに独立しています。PRAGMA AUTONOMOUS_TRANSACTIONはトランザクション独立性、AUTHIDは権限解釈、と異なる軸の機能です。組み合わせて「Invoker Rights+自律トランザクション」のような実装は可能で、監査ログを呼出し者の権限で書く用途などで使います。
QINVOKER RIGHTSでビューを参照すると挙動は?
AビューがBEQUEATH DEFINER(デフォルト)ならビュー所有者の権限で評価されます。BEQUEATH CURRENT_USERのビューなら呼出し者の権限で評価されます。Invoker Rightsプロシージャからビューを呼ぶときはビューのBEQUEATHも要確認です。
QパッケージSPECとBODYで違うAUTHIDを書ける?
A書けません。AUTHIDはSPECにだけ書き、BODYは自動的に同じAUTHIDで動作します。BODYに書いても無視されます(コンパイルエラーにはなりません)。混乱を避けるため、AUTHIDの記述はSPECのみに統一してください。
Qパッケージから別パッケージを呼ぶときAUTHIDはどう作用する?
A「呼び出された側」のAUTHIDが優先されます。Invoker pkg_a が Definer pkg_b を呼ぶと、pkg_b内では DEFINER の権限で実行されます。逆に Definer pkg_a が Invoker pkg_b を呼ぶと、pkg_b内では呼出し元のSESSION_USERの権限で実行されます。12c以降ではINHERIT PRIVILEGESによる制御が必要なので注意。
QAUTHIDを変更したパッケージは依存先に影響する?
AAUTHID変更は実装変更ではないので、直接の依存先(呼び出し側)はINVALIDになりません。ただし権限解釈と名前解決が変わるので、実行時に権限不足や名前解決失敗になる可能性があります。前述のチェックリストに従って依存先のテストを必ず実施してください。

関連記事で深掘りする

権限管理に関連する記事を集めました。

まとめ|AUTHIDを正しく選んで安全な権限設計

Definer RightsとInvoker Rightsは「どちらが優れている」のではなく、用途で正しく選ぶものです。内部動作・名前解決・ロールの扱いを理解し、12c以降のINHERIT PRIVILEGESを使いこなせれば、権限事故のないPL/SQL設計が可能になります。本記事の要点を7つに集約します。

  1. 業務APIで内部表を隠したいならDefiner、ライブラリ的な共通処理ならInvoker
  2. Definer RightsではロールでGRANTした権限が無効。必ず直接GRANT
  3. Invoker Rightsの名前解決は呼出し者基準。完全修飾名で曖昧さを排除
  4. 12c以降はINHERIT PRIVILEGESで権限昇格を制御(PUBLICからのREVOKE推奨)
  5. ビューはBEQUEATH句で同等の制御。トリガーは常にDefiner固定
  6. パッケージ単位でAUTHIDは1つ。混在が必要なら分割
  7. 切り替えは依存先全洗い出し→ステージング検証→段階的本番展開

権限設計は「分かったつもり」で進めると本番で必ず躓く領域です。本記事の判断フローと内部動作を押さえてから実装することで、権限不足エラー・想定外の権限昇格・ロール無効化の罠といった典型事故を構造的に防げます。深掘りが必要な領域はAUTHID設計のベストプラクティスセキュリティパッケージ設計を併せて参照してください。