【Oracle】ユーザーごとに接続制限を設定する方法|SESSIONS_PER_USER・CONNECT_TIME・ログオントリガー・アカウントロックまで解説

【Oracle】ユーザーごとに接続制限を設定する方法|SESSIONS_PER_USER・CONNECT_TIME・ログオントリガー・アカウントロックまで解説 Oracle

Oracle ではプロファイルを使ってユーザーごとに同時接続数・CPU 使用量・接続時間などのリソース制限を設定できます。さらにログオントリガーを使えば時間帯や IP アドレスによるログイン制御も可能です。

本記事では、プロファイルのリソース制限RESOURCE_LIMIT パラメータの有効化ログオントリガーによる高度な制御アカウントのロック/アンロックまで解説します。

この記事でわかること
・プロファイルのリソース制限パラメータ一覧
・RESOURCE_LIMIT パラメータの有効化(リソース制限を機能させる前提条件)
・SESSIONS_PER_USER で同時接続数を制限する方法
・CONNECT_TIME / IDLE_TIME で接続時間を制限する方法
・ログオントリガーで時間帯 / IP アドレスを制限する方法
・アカウントのロック / アンロック
・FAILED_LOGIN_ATTEMPTS でログイン失敗時のロック設定
スポンサーリンク

前提: RESOURCE_LIMIT パラメータの有効化

RESOURCE_LIMIT = TRUE にしないとリソース制限は機能しない
プロファイルのリソース制限(SESSIONS_PER_USER / CPU_PER_SESSION / CONNECT_TIME 等)は、RESOURCE_LIMIT パラメータが TRUE でないと無視されます。パスワード制限(PASSWORD_LIFE_TIME 等)は RESOURCE_LIMIT に関係なく常に有効です。
SQL(RESOURCE_LIMIT の確認と有効化)
-- 現在の設定を確認
SHOW PARAMETER resource_limit;
-- デフォルト: FALSE(リソース制限は無効)

-- 有効化(即時反映、再起動不要)
ALTER SYSTEM SET resource_limit = TRUE SCOPE=BOTH;

プロファイルのリソース制限パラメータ

パラメータ デフォルト 単位 説明
SESSIONS_PER_USER UNLIMITED ユーザーあたりの同時セッション数の上限
CONNECT_TIME UNLIMITED 1 セッションの最大接続時間。超過すると自動切断
IDLE_TIME UNLIMITED アイドル状態の最大時間。超過すると自動切断
CPU_PER_SESSION UNLIMITED 1/100 秒 1 セッションあたりの最大 CPU 使用時間
CPU_PER_CALL UNLIMITED 1/100 秒 1 回の SQL 実行あたりの最大 CPU 時間
LOGICAL_READS_PER_SESSION UNLIMITED ブロック 1 セッションの最大論理読み取りブロック数
LOGICAL_READS_PER_CALL UNLIMITED ブロック 1 回の SQL 実行の最大論理読み取りブロック数
PRIVATE_SGA UNLIMITED バイト 共有サーバーモード時の最大 SGA 使用量
COMPOSITE_LIMIT UNLIMITED 上記リソースの加重合計の上限
リソース制限はプロファイルで設定し、ユーザーに割り当てる
リソース制限はプロファイル単位で定義し、ALTER USER … PROFILE でユーザーに適用します。同じプロファイルを複数ユーザーに適用できるため、ロール別(開発者用 / アプリ用 / DBA 用)に管理するのが効率的です。

SESSIONS_PER_USER で同時接続数を制限する

SQL(同時接続数制限)
-- 同時接続 3 セッションまでに制限するプロファイル
CREATE PROFILE limited_session LIMIT
    SESSIONS_PER_USER 3;

-- ユーザーに適用
ALTER USER dev_user PROFILE limited_session;

-- 4 つ目のセッションを開こうとすると:
-- ORA-02391: exceeded simultaneous SESSIONS_PER_USER limit
SQL(現在のセッション数を確認)
-- ユーザーごとの現在のセッション数
SELECT username, COUNT(*) AS session_count
FROM v$session
WHERE username IS NOT NULL
GROUP BY username
ORDER BY session_count DESC;

CONNECT_TIME / IDLE_TIME で接続時間を制限する

SQL(接続時間制限)
-- 接続時間 60 分、アイドル 15 分で自動切断するプロファイル
CREATE PROFILE time_limited LIMIT
    CONNECT_TIME 60      -- 最大接続時間: 60 分
    IDLE_TIME    15;     -- アイドル制限: 15 分

ALTER USER dev_user PROFILE time_limited;

-- CONNECT_TIME 超過: ORA-02399 で自動切断
-- IDLE_TIME 超過: ORA-02396 で自動切断
IDLE_TIME の活用場面
・SQL*Plus を開いたまま放置するユーザーへの対策
・アプリケーション接続プールの放置セッション対策
・データベースのセッション枯渇を防止
ただしアプリケーションの接続プール(JDBC 等)が IDLE_TIME で切断されないよう、プール側の keep-alive 設定を確認してください。

実用的なプロファイル設計例

SQL(ロール別プロファイル)
-- 開発者用: 接続制限あり、パスワード制限は緩め
CREATE PROFILE dev_profile LIMIT
    SESSIONS_PER_USER   5
    CONNECT_TIME        480    -- 8 時間
    IDLE_TIME           30     -- 30 分
    PASSWORD_LIFE_TIME  UNLIMITED
    FAILED_LOGIN_ATTEMPTS 10;

-- アプリ接続用: セッション数は多め、時間制限なし
CREATE PROFILE app_profile LIMIT
    SESSIONS_PER_USER   100
    CONNECT_TIME        UNLIMITED
    IDLE_TIME           UNLIMITED
    PASSWORD_LIFE_TIME  UNLIMITED
    FAILED_LOGIN_ATTEMPTS 5;

-- DBA 用: 制限なし
CREATE PROFILE dba_profile LIMIT
    SESSIONS_PER_USER   UNLIMITED
    CONNECT_TIME        UNLIMITED
    IDLE_TIME           UNLIMITED
    PASSWORD_LIFE_TIME  90
    FAILED_LOGIN_ATTEMPTS 3;

-- ユーザーに割り当て
ALTER USER dev_user PROFILE dev_profile;
ALTER USER app_user PROFILE app_profile;
ALTER USER admin_user PROFILE dba_profile;

ログオントリガーで高度な接続制御

プロファイルでは対応できない時間帯制限IP アドレス制限は、AFTER LOGON トリガーで実現します。

時間帯によるログイン制限

SQL(業務時間外のログインを禁止)
-- 22:00〜7:00 の間はログインを禁止
CREATE OR REPLACE TRIGGER trg_restrict_logon_time
AFTER LOGON ON DATABASE
BEGIN
    IF USER NOT IN ('SYS', 'SYSTEM') THEN
        IF TO_NUMBER(TO_CHAR(SYSDATE, 'HH24')) >= 22
           OR TO_NUMBER(TO_CHAR(SYSDATE, 'HH24')) < 7 THEN
            RAISE_APPLICATION_ERROR(-20001,
                '22:00-7:00 の間はログインできません');
        END IF;
    END IF;
END;
/

IP アドレスによるログイン制限

SQL(許可 IP 以外のログインを禁止)
-- 特定 IP アドレスからのみ接続を許可
CREATE OR REPLACE TRIGGER trg_restrict_logon_ip
AFTER LOGON ON DATABASE
DECLARE
    v_ip VARCHAR2(100);
BEGIN
    IF USER = 'ADMIN_USER' THEN
        v_ip := SYS_CONTEXT('USERENV', 'IP_ADDRESS');
        IF v_ip NOT IN ('10.0.1.100', '10.0.1.101', '192.168.1.50') THEN
            RAISE_APPLICATION_ERROR(-20002,
                'このIPアドレスからの接続は許可されていません: ' || v_ip);
        END IF;
    END IF;
END;
/

同時接続数の高度な制限(プロファイルの代替)

SQL(ログオントリガーでセッション数を制限)
-- RESOURCE_LIMIT を TRUE にできない環境での代替手段
CREATE OR REPLACE TRIGGER trg_limit_sessions
AFTER LOGON ON DATABASE
DECLARE
    v_count NUMBER;
BEGIN
    IF USER = 'APP_USER' THEN
        SELECT COUNT(*) INTO v_count
        FROM v$session WHERE username = 'APP_USER';
        IF v_count > 50 THEN
            RAISE_APPLICATION_ERROR(-20003,
                'APP_USER のセッション数が上限(50)を超えています');
        END IF;
    END IF;
END;
/
ログオントリガーのエラーでログインが完全にブロックされるリスク
トリガーにバグがあると全ユーザーがログインできなくなる場合があります。SYS / SYSTEM ユーザーはトリガーの対象外にしておいてください。万が一の場合は sqlplus / as sysdba で接続してトリガーを DROP します。

アカウントのロック / アンロック

SQL(手動ロック / アンロック)
-- アカウントをロック(ログイン不可にする)
ALTER USER dev_user ACCOUNT LOCK;

-- アカウントをアンロック
ALTER USER dev_user ACCOUNT UNLOCK;

-- 状態の確認
SELECT username, account_status, lock_date
FROM dba_users
WHERE username = 'DEV_USER';

FAILED_LOGIN_ATTEMPTS による自動ロック

SQL(ログイン失敗回数による自動ロック)
-- 5 回失敗で自動ロック、1 時間後に自動アンロック
CREATE PROFILE strict_login LIMIT
    FAILED_LOGIN_ATTEMPTS 5
    PASSWORD_LOCK_TIME    1/24;  -- 1/24 日 = 1 時間

ALTER USER target_user PROFILE strict_login;

-- PASSWORD_LOCK_TIME = UNLIMITED の場合: DBA が手動でアンロックするまで永久ロック
-- PASSWORD_LOCK_TIME = 1 の場合: 1 日後に自動アンロック
account_status 意味 対処
OPEN 正常
LOCKED 手動でロックされた ALTER USER … ACCOUNT UNLOCK
LOCKED(TIMED) ログイン失敗で自動ロック PASSWORD_LOCK_TIME 経過後に自動解除、または手動 UNLOCK
EXPIRED パスワード期限切れ ALTER USER … IDENTIFIED BY new_pw
EXPIRED & LOCKED 期限切れ + ロック ALTER USER … IDENTIFIED BY new_pw ACCOUNT UNLOCK

現在の設定を確認する

SQL(ユーザーごとのプロファイルとリソース制限を確認)
-- ユーザーのプロファイル割り当てを確認
SELECT username, profile, account_status
FROM dba_users
WHERE username NOT IN ('SYS','SYSTEM','ANONYMOUS','XDB')
ORDER BY profile, username;

-- プロファイルのリソース制限を確認
SELECT profile, resource_name, limit
FROM dba_profiles
WHERE resource_type = 'KERNEL'  -- リソース制限
ORDER BY profile, resource_name;

-- パスワード制限を確認
SELECT profile, resource_name, limit
FROM dba_profiles
WHERE resource_type = 'PASSWORD'
ORDER BY profile, resource_name;

実務パターン集

パターン(1): 開発者の同時接続を 3 に制限

SQL
ALTER SYSTEM SET resource_limit = TRUE SCOPE=BOTH;

CREATE PROFILE dev_limited LIMIT
    SESSIONS_PER_USER 3
    IDLE_TIME 30;

ALTER USER dev_user PROFILE dev_limited;

パターン(2): 退職者のアカウントを即時ロック

SQL
-- 退職者のアカウントを即時ロック
ALTER USER ex_employee ACCOUNT LOCK;

-- 既存セッションの強制切断(必要に応じて)
-- SID / SERIAL# を確認
SELECT sid, serial# FROM v$session WHERE username = 'EX_EMPLOYEE';
-- 切断
ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;

パターン(3): 本番 DB に夜間のみ接続を許可

SQL
-- 業務時間(9:00〜18:00)のみ接続を許可するトリガー
CREATE OR REPLACE TRIGGER trg_business_hours_only
AFTER LOGON ON DATABASE
BEGIN
    IF USER = 'BATCH_USER' THEN
        IF TO_NUMBER(TO_CHAR(SYSDATE, 'HH24')) BETWEEN 9 AND 17 THEN
            RAISE_APPLICATION_ERROR(-20010,
                'BATCH_USER は業務時間中(9:00-18:00)は接続できません');
        END IF;
    END IF;
END;
/

パターン(4): アイドルセッションの一括切断

SQL(30 分以上アイドルのセッションを一括切断)
-- 30 分以上アイドルのユーザーセッションを確認
SELECT sid, serial#, username, status,
       last_call_et/60 AS idle_minutes
FROM v$session
WHERE status = 'INACTIVE'
  AND type = 'USER'
  AND last_call_et > 1800;  -- 1800 秒 = 30 分

-- 一括切断用 SQL を生成
SELECT 'ALTER SYSTEM KILL SESSION ''' || sid || ',' || serial# || ''' IMMEDIATE;'
FROM v$session
WHERE status = 'INACTIVE' AND type = 'USER' AND last_call_et > 1800;

よくある質問

QRESOURCE_LIMIT = FALSE のままだとどうなりますか?
Aプロファイルのリソース制限(SESSIONS_PER_USER / CONNECT_TIME / IDLE_TIME 等)がすべて無視されます。パスワード制限(PASSWORD_LIFE_TIME / FAILED_LOGIN_ATTEMPTS 等)は RESOURCE_LIMIT に関係なく常に有効です。リソース制限を使うなら必ず TRUE に設定してください。
QIDLE_TIME で接続プールのセッションが切断されてしまいます
AJDBC 等の接続プールは使用していないセッションをプール内に保持するため、IDLE_TIME で切断される可能性があります。対策は 2 つあります。(1) 接続プール側で keep-alive / validation query を設定して定期的にセッションを使用する。(2) アプリケーションユーザーの IDLE_TIME を UNLIMITED にする。
Qログオントリガーのバグで全員ログインできなくなりました
Asqlplus / as sysdba(OS 認証)で接続できます。SYS ユーザーは AFTER LOGON ON DATABASE トリガーの影響を受けません。接続後に DROP TRIGGER trigger_name; で問題のトリガーを削除してください。
QSESSIONS_PER_USER は接続プールのセッションもカウントされますか?
Aはい。接続プールが保持するセッションも v$session にカウントされます。アプリケーション接続プールのサイズ(max-pool-size)と SESSIONS_PER_USER の値を合わせて設計してください。
Qロックされたユーザーの既存セッションはどうなりますか?
AALTER USER … ACCOUNT LOCK を実行しても、既存のセッションは切断されません。新規ログインのみがブロックされます。既存セッションも切断したい場合は ALTER SYSTEM KILL SESSION を使ってください。
Qプロファイルを変更したら即座に反映されますか?
Aはい。ALTER PROFILE の変更は即時反映されます。ただし、既に接続中のセッションに対しては次のリソースチェック時(SQL 実行時等)に適用されます。既存セッションの即時切断には反映されません。

まとめ

ユーザーごとの接続制限の要点をまとめます。

やりたいこと 方法
リソース制限を有効化(前提条件) ALTER SYSTEM SET resource_limit = TRUE SCOPE=BOTH
同時接続数を制限 CREATE PROFILE … LIMIT SESSIONS_PER_USER N
接続時間を制限 CREATE PROFILE … LIMIT CONNECT_TIME N
アイドル時間で自動切断 CREATE PROFILE … LIMIT IDLE_TIME N
時間帯でログインを制限 AFTER LOGON ON DATABASE トリガーで RAISE_APPLICATION_ERROR
IP アドレスでログインを制限 SYS_CONTEXT(‘USERENV’, ‘IP_ADDRESS’) をトリガーで判定
アカウントを手動ロック ALTER USER … ACCOUNT LOCK
ログイン失敗で自動ロック FAILED_LOGIN_ATTEMPTS N + PASSWORD_LOCK_TIME N

プロファイルの全パラメータは「ユーザープロファイル完全ガイド」、パスワード有効期限は「パスワードの有効期限を無制限にする方法」、ユーザーの作成と権限は「ユーザー作成と権限付与の完全ガイド」も併せて参照してください。