Oracle の運用現場で必ず出てくる悩みが「アプリケーションスキーマのパスワードをどう扱うか」です。開発者や保守担当が共通のスキーマユーザー(例: APP_OWNER)で接続すると、監査ログに残る「誰が操作したか」は APP_OWNER 固定になり、内部統制の観点では致命的です。かといって個人ユーザーに APP_OWNER の全権を付与して回るのも、権限設計が崩壊します。
この問題を Oracle 標準機能だけで解決するのが プロキシユーザー(Proxy User / CONNECT THROUGH)です。個人ユーザー(プロキシ)の認証情報で接続し、実行権限はアプリスキーマ(ターゲット)として働く——監査証跡には「プロキシとターゲットの両方」が残ります。この記事では ALTER USER ... GRANT CONNECT THROUGH の全構文、ロール制限、3 種類の認証オプション、SQL*Plus / JDBC / SQL Developer からの接続方法、DBA_PROXIES と UNIFIED_AUDIT_TRAIL による実ユーザー追跡まで、2026 年 4 月時点の Oracle 19c / 23ai の仕様を前提に網羅解説します。
プロキシユーザーとは何か
プロキシユーザーは「自分の認証情報で、別ユーザーとしてログインする」仕組みです。図式化すると以下の流れになります。
| 登場人物 | 役割 | 認証情報の扱い |
|---|---|---|
| プロキシ(Proxy User) | 実際に接続する個人ユーザー(例: TANAKA) |
このユーザーのパスワードで認証する |
| ターゲット(Client User) | 最終的に振る舞うスキーマ(例: APP_OWNER) |
通常パスワード不要。実行時の権限はこのユーザー |
| 認可設定 | ALTER USER target GRANT CONNECT THROUGH proxy |
誰が誰として振る舞えるかを DB 側で定義 |
DROP USER するだけで退場させられます。基本構文 ── ALTER USER … GRANT CONNECT THROUGH
プロキシ関係の定義は、必ず ターゲット側の ALTER USER で行います。「target に対して、proxy が CONNECT THROUGH できる」という読み方です。
-- ① まずプロキシとターゲットを作成(既存であればスキップ) CREATE USER tanaka IDENTIFIED BY "Tanaka#Pass_2026"; CREATE USER app_owner IDENTIFIED BY "App#Owner_2026"; GRANT CREATE SESSION TO tanaka; -- ② tanaka が app_owner として接続できるように認可 ALTER USER app_owner GRANT CONNECT THROUGH tanaka; -- ③ 解除(やり方は逆に target 側で REVOKE) ALTER USER app_owner REVOKE CONNECT THROUGH tanaka;
CREATE SESSION が必要ありません。 プロキシ経由で接続する場合、ターゲットが自分で直接ログインすることは想定しないため、CREATE SESSION を付けないでおくと、ターゲットのパスワードが漏れても直接ログインは阻止できます。これはプロキシユーザー運用のセキュリティ上の大きな利点です。接続方法 ── SQL*Plus / JDBC / SQL Developer
SQL*Plus での接続構文
SQL*Plus は [ターゲット] をユーザー名の後に角括弧で付けます。シェル環境によっては括弧をクォートする必要があります。
# 基本構文: sqlplus プロキシ[ターゲット]/プロキシのパスワード@接続識別子 sqlplus tanaka[app_owner]/Tanaka#Pass_2026@orclpdb1 # bash/zsh では角括弧を明示クォート(ファイル名展開を防ぐ) sqlplus "tanaka[app_owner]"/Tanaka#Pass_2026@orclpdb1 # CONNECT コマンドでも同じ書き方 SQL> CONNECT tanaka[app_owner]/Tanaka#Pass_2026@orclpdb1 # 接続後、セッションは app_owner として動く SQL> SHOW USER USER は "APP_OWNER"
JDBC Thin でのプロキシ接続
JDBC Thin ドライバはプロキシ専用の API(OracleConnection.openProxySession())を用意しています。最初にプロキシの認証情報で接続し、後からプロキシセッションを開く 2 段階構成です。
import java.sql.*;
import java.util.Properties;
import oracle.jdbc.OracleConnection;
// ① プロキシユーザーで普通に接続
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@//db.example.com:1521/orclpdb1",
"tanaka",
"Tanaka#Pass_2026"
);
// ② プロキシセッションに切り替え
Properties prop = new Properties();
prop.put(OracleConnection.PROXY_USER_NAME, "app_owner");
// パスワード認証を要求されている場合のみ
// prop.put(OracleConnection.PROXY_USER_PASSWORD, "App#Owner_2026");
((OracleConnection) conn).openProxySession(
OracleConnection.PROXYTYPE_USER_NAME, prop);
// ③ この時点からセッションは app_owner として動く
try (Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT USER FROM dual")) {
while (rs.next()) {
System.out.println(rs.getString(1)); // APP_OWNER
}
}
SQL Developer での設定
SQL Developer では接続プロパティの 「プロキシ接続」 タブで「Proxy User」に実際に認証するプロキシを、通常の「ユーザー名」欄にターゲットを指定します。SQL*Plus の proxy[target]/pw と同じことを GUI でやる形です。
3 種類の認証オプション
プロキシ関係には「ターゲット側の追加認証をどうするか」で 3 つの選択肢があります。セキュリティ要件に応じて使い分けます。
① デフォルト(プロキシの認証のみ)
ALTER USER app_owner GRANT CONNECT THROUGH tanaka; -- 接続: プロキシのパスワードだけで OK -- sqlplus tanaka[app_owner]/Tanaka#Pass@db
もっともシンプル。個人認証だけ通れば、ターゲットのパスワードを知らなくても(むしろ知らないまま)プロキシできる。日常運用ではこれが基本形です。
② AUTHENTICATED USING PASSWORD(ターゲットのパスワードも要求)
ALTER USER app_owner GRANT CONNECT THROUGH tanaka AUTHENTICATED USING PASSWORD; -- 接続: ターゲットのパスワードも送る必要がある -- sqlplus tanaka[app_owner/App#Owner_2026]/Tanaka#Pass@db -- ※ Oracle 内部では AUTHENTICATION REQUIRED に変換される
③ AUTHENTICATED USING DISTINGUISHED NAME(証明書 / DN)
-- ターゲットをグローバルユーザーで作成 CREATE USER jeff IDENTIFIED GLOBALLY AS 'CN=jeff,OU=americas,O=oracle,L=redwoodshores,ST=ca,C=us'; -- プロキシに DN 認証を設定 ALTER USER jeff GRANT CONNECT THROUGH hr AUTHENTICATED USING DISTINGUISHED NAME;
AUTHENTICATION REQUIRED を省略したのと同等の扱いになります。Oracle Internet Directory(OID)や OCI IAM などのエンタープライズ認証基盤と連携する場合にのみ使う上級オプションです。WITH ROLE ── 権限を絞り込む
プロキシで接続した瞬間、ターゲットが持つすべてのロールがデフォルトで有効化されます。これを絞り込むのが WITH ROLE 句です。「最小権限の原則」を守るためにも、役割が限定される場合は必ずロール制限を掛けるべきです。
-- ① 特定ロールだけ有効化(read_role のみ) ALTER USER app_owner GRANT CONNECT THROUGH readonly_user WITH ROLE read_role; -- ② 複数ロールをカンマ区切りで ALTER USER app_owner GRANT CONNECT THROUGH support_user WITH ROLE read_role, support_role; -- ③ 指定ロール以外すべて(デバッグ用ロールを除外) ALTER USER app_owner GRANT CONNECT THROUGH admin_user WITH ROLE ALL EXCEPT debug_role; -- ④ すべてのロールを無効化(超最小) ALTER USER app_owner GRANT CONNECT THROUGH audit_user WITH NO ROLES;
プロキシ関係の確認 ── DBA_PROXIES / V$SESSION
DBA_PROXIES ── 現在の認可設定一覧
SELECT proxy, -- プロキシユーザー名 client, -- ターゲット(クライアント)ユーザー名 authentication, -- N / Y(AUTHENTICATION REQUIRED か) authorization_constraint, -- PROXY MAY ACTIVATE ALL CLIENT ROLES / NO CLIENT ROLES など role, -- WITH ROLE で許可されているロール flags -- PROXY MAY ACTIVATE ROLE 等のフラグ FROM dba_proxies ORDER BY client, proxy; -- USER_LEVEL で見るには PROXY_USERS ビュー(自分がプロキシできる相手のみ)
V$SESSION ── 稼働中のプロキシセッション可視化
SELECT s.sid, s.serial#, s.username AS target_user, -- app_owner p.username AS proxy_user, -- tanaka s.osuser, s.machine, s.program, s.logon_time, s.proxy_sessionid AS proxy_sid -- プロキシセッションの識別子 FROM v$session s LEFT JOIN v$session p ON s.proxy_sessionid = p.sid WHERE s.proxy_sessionid IS NOT NULL ORDER BY s.logon_time DESC;
PROXY_SESSIONID が NULL です。値が入っていれば必ずプロキシ接続。USERNAME はターゲットで、プロキシ本人を知りたい時は PROXY_SESSIONID を使って V$SESSION を自己結合します。SYS_CONTEXT でセッションの内実を見る
SELECT
SYS_CONTEXT('USERENV','SESSION_USER') AS session_user, -- APP_OWNER(ターゲット)
SYS_CONTEXT('USERENV','PROXY_USER') AS proxy_user, -- TANAKA(プロキシ)
SYS_CONTEXT('USERENV','AUTHENTICATED_IDENTITY') AS authn_user, -- TANAKA
SYS_CONTEXT('USERENV','IDENTIFICATION_TYPE') AS id_type -- PROXY 等
FROM dual;
-- プロキシ接続でない時は PROXY_USER が NULL
監査ログで実ユーザーを追跡する
プロキシユーザーの最大の価値は「監査で実ユーザーが追える」ことです。Unified Audit では DBUSERNAME(ターゲット)と DBPROXY_USERNAME(プロキシ)が別カラムで記録され、「APP_OWNER として何をした」と「それを実行した実ユーザーは誰だった」が両方わかります。
-- Unified Audit が有効(12c 以降デフォルト)前提
SELECT event_timestamp,
dbproxy_username AS proxy_user, -- 個人(TANAKA)
dbusername AS target_user, -- スキーマ(APP_OWNER)
os_username,
action_name,
SUBSTR(sql_text, 1, 80) AS sql_text
FROM unified_audit_trail
WHERE dbproxy_username IS NOT NULL
AND event_timestamp > SYSDATE - 1
ORDER BY event_timestamp DESC
FETCH FIRST 100 ROWS ONLY;
SELECT event_timestamp,
dbusername,
action_name,
object_schema || '.' || object_name AS target_obj,
SUBSTR(sql_text, 1, 120) AS sql_text
FROM unified_audit_trail
WHERE dbproxy_username = 'TANAKA'
AND event_timestamp BETWEEN TIMESTAMP '2026-01-01 00:00:00'
AND TIMESTAMP '2026-04-01 00:00:00'
ORDER BY event_timestamp;
DBA_AUDIT_TRAIL に十分に残らないケースがあります。2026 年時点では Unified Audit への移行が強く推奨されています。詳細は 統合監査(Unified Audit)完全ガイド を参照してください。実務ユースケースと移行パターン
ユースケース① 共有アカウント運用の解消
「APP_OWNER のパスワードを開発チーム全員で共有している」という状態を、監査可能な形に移行する典型パターンです。
- 各メンバーに個人ユーザー(
TANAKA、SATO、SUZUKI…)を作成 - APP_OWNER を対象に
GRANT CONNECT THROUGHで全員を認可 - APP_OWNER から
CREATE SESSIONを剥奪して直接ログインを封じる - APP_OWNER のパスワードを強制ローテーションし、金庫に封印
- 監査で
DBPROXY_USERNAME IS NOT NULLが常態になっていることを確認
ユースケース② 参照専用 BI ツール接続
BI ツールが APP_OWNER にフル権限で接続していると、誤操作で UPDATE / DELETE が走るリスクがあります。プロキシと WITH ROLE で参照のみに絞り込みます。
-- ① 参照専用ロールを作成 CREATE ROLE app_read_only; GRANT SELECT ANY TABLE TO app_read_only; -- または個別テーブル -- ② BI 接続用のプロキシユーザー CREATE USER bi_readonly IDENTIFIED BY "BIRead#2026"; GRANT CREATE SESSION TO bi_readonly; -- ③ app_read_only ロールだけ有効にしてプロキシ ALTER USER app_owner GRANT CONNECT THROUGH bi_readonly WITH ROLE app_read_only; -- BI ツールは bi_readonly[app_owner] で接続 -- → UPDATE / DELETE はロールに含まれないため実行不可
ユースケース③ 自動化 / バッチからの接続
CI/CD や夜間バッチが接続する場合、ジョブごとに専用プロキシを作るとログで追跡しやすくなります。ジョブを廃止する時は該当プロキシを DROP USER するだけで、アプリスキーマに影響を与えずに撤去できます。
ユースケース④ マルチテナント環境での PDB 管理
CDB/PDB 構成で、PDB 内のアプリスキーマを複数の DBA で管理する場合、各 DBA にプロキシ経由でアクセスさせると、どの DBA がどの PDB を触ったかが監査で追えます。マルチテナントの全体設計は マルチテナント完全ガイド を参照してください。
プロキシ関係の解除と棚卸し
-- ① 個別解除(target の ALTER USER で REVOKE)
ALTER USER app_owner REVOKE CONNECT THROUGH tanaka;
-- ② 特定ユーザーがプロキシできる相手を全部洗い出し
SELECT proxy, client
FROM dba_proxies
WHERE proxy = 'TANAKA';
-- ③ 退職者のプロキシを一括解除(PL/SQL 例)
BEGIN
FOR r IN (SELECT client FROM dba_proxies WHERE proxy = 'RETIRED_USER') LOOP
EXECUTE IMMEDIATE 'ALTER USER ' || r.client ||
' REVOKE CONNECT THROUGH retired_user';
END LOOP;
EXECUTE IMMEDIATE 'DROP USER retired_user CASCADE';
END;
/
DROP USER ... CASCADE すると、DBA_PROXIES の関連エントリも自動的に消えます。ただしターゲット側のオブジェクト(スキーマのテーブルなど)には影響しません。個人単位でアクセス停止できるのがプロキシ運用の最大の利点です。落とし穴と注意点
プロキシに付与した権限は接続後は無効になる
プロキシユーザー自身に SELECT ANY TABLE などを付与しても、プロキシ経由で接続した後はターゲットの権限で動くため、プロキシ側の権限は一切使えません。プロキシにはログインに必要な CREATE SESSION だけ付与するのが原則です。
AUTHENTICATION REQUIRED はクライアント実装依存
AUTHENTICATED USING PASSWORD を指定すると、ターゲットのパスワードを JDBC / OCI の接続文字列に含める必要があります。多くの JDBC プールはこのパターンをサポートしていないため、一般的な Web アプリでは使いにくい構成です。安易に付けると運用が詰みます。
プロキシセッションは ALTER SESSION SET CURRENT_SCHEMA とは別物
ALTER SESSION SET CURRENT_SCHEMA = app_owner はスキーマ名の解決先を変えるだけで、権限はプロキシユーザーのままです。「実行者は APP_OWNER」にしたいならプロキシが必須です。混同しないように注意。
SQL*Plus の角括弧はシェルで展開される
bash / zsh で sqlplus tanaka[app_owner]/pw@db を書くと、シェルが [app_owner] をグロブ展開しようとして失敗することがあります。必ず "tanaka[app_owner]" のようにクォートしてください。
ダブルクォートで囲んだユーザー名は大文字小文字区別
Oracle のユーザー名は通常大文字化されますが、CREATE USER "tanaka" のようにダブルクォートで作ったユーザー名は小文字のまま登録されます。プロキシ関係の ALTER USER でも同じ表記を使う必要があります。混在するとメンテ時に必ずハマるため、組織として命名規則を統一してください。
よくある質問
DBUSERNAME(ターゲット)と DBPROXY_USERNAME(個人)を両方記録するため、「APP_OWNER として発行された SQL を、実際には TANAKA が実行した」という 2 軸で記録が残ります。スキーマ所有者単位のアクセス制御を維持しつつ個人認証が欲しい時はプロキシが唯一の解です。sqlplus tanaka[app_owner]/pw@db で接続すると CURRENT_SCHEMA = APP_OWNER の状態で始まるため、スキーマ修飾なしで APP_OWNER のオブジェクトにアクセスできます。追加で別スキーマに切り替えたい場合は ALTER SESSION SET CURRENT_SCHEMA を使えますが、権限はプロキシセッションのまま(ターゲット+WITH ROLE 指定分)なので注意してください。CONNECT THROUGH できますが、管理権限(SYSDBA)はプロキシ経由では継承されない挙動があり、想定通り動かない場合があります。SYS への個人認証が欲しい場合はプロキシではなく、個人 DBA ユーザーに SYSDBA 権限を直接付与する運用(SYS・SYSTEM・SYSDBA の違い完全ガイド参照)のほうがシンプルで監査しやすいです。PROXYTYPE_USER_NAME を明示的にサポートしており、プール内の物理接続はプロキシユーザーで張り、論理接続ごとに異なるターゲットに openProxySession() できます。Web アプリで「リクエストごとにエンドユーザーとしてふるまう」実装が可能になるため、DBA_AUDIT レベルで個人まで追跡したいシステムに最適です。PASSWORD_LIFE_TIME)になると ORA-28001 でログイン自体が不可能になります。ターゲットは直接 CREATE SESSION を持たない設計が推奨なので、対処は個人プロキシのパスワードを変更するだけです。プロファイル設計は プロファイル完全ガイド を参考にしてください。sqlplus tanaka[app_readonly]/pw@db)。1 つのセッションで複数スキーマを扱いたい場合は ALTER SESSION SET CURRENT_SCHEMA を使いますが、権限は変わらないためアクセス制御の目的では不十分です。GRANT CONNECT THROUGH を設定するだけでは既存の直接接続には影響しません。既存接続を強制的にプロキシ化したい場合は、ターゲットから CREATE SESSION 権限を剥奪します(REVOKE CREATE SESSION FROM app_owner)。ただし剥奪するとアプリが一斉に接続できなくなるため、必ず先にアプリ側の接続文字列をプロキシ形式に変更してからリリースしてください。ALTER USER ... GRANT CONNECT THROUGH が利用可能で、OCI IAM との統合プロキシ認証もサポートされています。特にマルチテナント SaaS や BaaS でのマルチユーザー運用では、ADB 側のプロキシと OCI IAM の統合が個人トレーサビリティの標準構成になります。まとめ
- プロキシユーザーは「個人認証 × スキーマ権限」を両立する仕組み。ターゲットのパスワードを配らずに個人単位で追跡可能な接続が実現できる
- 構文は
ALTER USER target GRANT CONNECT THROUGH proxy。必ずターゲット側で実行する - 認証は 3 種類(デフォルト / AUTHENTICATED USING PASSWORD / DISTINGUISHED NAME)。基本はデフォルトで運用。PASSWORD 指定は互換性要件がなければ使わない
- WITH ROLE / WITH NO ROLES / WITH ROLE ALL EXCEPT でロール制限。参照専用 BI や自動バッチは必ず絞る
- SQL*Plus は
proxy[target]/pw@db形式、JDBC Thin はopenProxySession()。SQL Developer など商用ツールも多くが対応 - 確認ビュー: DBA_PROXIES(認可設定)・V$SESSION.PROXY_SESSIONID(稼働中セッション)・SYS_CONTEXT(‘USERENV’,’PROXY_USER’)(アプリからの確認)
- 監査は UNIFIED_AUDIT_TRAIL.DBPROXY_USERNAME で実ユーザー追跡。退職者のアクセス履歴レビューもワンクエリで完結
- ターゲットから
CREATE SESSIONを剥奪して直接ログインを封じると、アプリスキーマのパスワード漏洩リスクが実質ゼロになる
権限確認の SQL 全体は Oracle ユーザ権限を確認する方法完全ガイド、管理ユーザーと管理権限の設計は SYS・SYSTEM・SYSDBA の違い完全ガイド、ユーザー作成から権限ロール管理の全体像は ユーザー・権限・ロール完全ガイド、パスワード有効期限や複雑性ポリシーは プロファイル完全ガイド、監査ログの読み方は 統合監査(Unified Audit)完全ガイド もあわせて参照してください。

