Oracle データベースへの不正アクセスを防ぐ最も基本的な対策の 1 つがIP アドレスによるアクセス制限です。Oracle ではsqlnet.ora、ログオントリガー、OS ファイアウォールの 3 つのレイヤーで IP 制限を実装できます。
本記事では、それぞれの設定方法と使い分け、サブネット指定、設定変更後の反映手順、自分自身を締め出さないための安全策まで解説します。
この記事でわかること
・sqlnet.ora の TCP.VALIDNODE_CHECKING / INVITED_NODES / EXCLUDED_NODES による制限
・ログオントリガーによる DB レベルの IP 制限
・OS ファイアウォール(iptables / firewalld / Windows)での制限
・3 つのレイヤーの使い分け
・サブネット / ホスト名での指定方法
・設定変更後の反映(リスナー再起動)
・自分自身を締め出さないための安全策
・sqlnet.ora の TCP.VALIDNODE_CHECKING / INVITED_NODES / EXCLUDED_NODES による制限
・ログオントリガーによる DB レベルの IP 制限
・OS ファイアウォール(iptables / firewalld / Windows)での制限
・3 つのレイヤーの使い分け
・サブネット / ホスト名での指定方法
・設定変更後の反映(リスナー再起動)
・自分自身を締め出さないための安全策
IP アクセス制限の 3 つのレイヤー
| レイヤー | 設定場所 | 制限の粒度 | 再起動 |
|---|---|---|---|
| sqlnet.ora(リスナーレベル) | sqlnet.ora ファイル | IP / サブネット / ホスト名 | リスナー再起動が必要 |
| ログオントリガー(DB レベル) | AFTER LOGON ON DATABASE トリガー | IP + ユーザー + 時間帯の組み合わせ | 即時反映(DDL) |
| OS ファイアウォール | iptables / firewalld / Windows FW | IP / ポート | OS コマンドで即時反映 |
多層防御が推奨
・OS ファイアウォール: ネットワークレベルで不要なポートをブロック(1521 を許可 IP のみに限定)
・sqlnet.ora: Oracle リスナーレベルで追加制限
・ログオントリガー: ユーザーごとの細かい IP 制限
1 つのレイヤーだけでなく複数のレイヤーで制限するのがセキュリティのベストプラクティスです。
・OS ファイアウォール: ネットワークレベルで不要なポートをブロック(1521 を許可 IP のみに限定)
・sqlnet.ora: Oracle リスナーレベルで追加制限
・ログオントリガー: ユーザーごとの細かい IP 制限
1 つのレイヤーだけでなく複数のレイヤーで制限するのがセキュリティのベストプラクティスです。
sqlnet.ora で IP アクセスを制限する
基本パラメータ
| パラメータ | 説明 |
|---|---|
| TCP.VALIDNODE_CHECKING | IP チェック機能の ON / OFF(YES で有効化) |
| TCP.INVITED_NODES | 許可する IP アドレスのリスト(ホワイトリスト) |
| TCP.EXCLUDED_NODES | 拒否する IP アドレスのリスト(ブラックリスト) |
sqlnet.ora(ホワイトリスト方式: 許可 IP のみ接続可能)
# sqlnet.ora のパス: # Linux: $ORACLE_HOME/network/admin/sqlnet.ora # Windows: %ORACLE_HOME%\network\admin\sqlnet.ora # IP チェックを有効化 TCP.VALIDNODE_CHECKING = YES # 許可する IP アドレス(これ以外は全て拒否) TCP.INVITED_NODES = (10.0.1.100, 10.0.1.101, 10.0.2.*, 192.168.1.0/24, localhost) # ※ INVITED_NODES を設定すると、リストにない IP は全て拒否される # ※ localhost(127.0.0.1)を必ず含めること
sqlnet.ora(ブラックリスト方式: 特定 IP だけ拒否)
TCP.VALIDNODE_CHECKING = YES # 拒否する IP アドレス(これ以外は全て許可) TCP.EXCLUDED_NODES = (192.168.100.50, 10.99.*)
INVITED_NODES に localhost を含めないと自分自身も接続不可になる
INVITED_NODES を設定する場合、
INVITED_NODES を設定する場合、
localhost と 127.0.0.1 を必ず含めてください。含めないとサーバー上の sqlplus / as sysdba でさえ TCP 接続が拒否される場合があります。サブネット / ワイルドカード / ホスト名の指定
| 指定方法 | 例 | 意味 |
|---|---|---|
| IP アドレス(単体) | 10.0.1.100 | 特定のホスト 1 台 |
| ワイルドカード | 10.0.2.* | 10.0.2.0〜10.0.2.255 の全ホスト |
| CIDR 表記 | 192.168.1.0/24 | 192.168.1.0〜192.168.1.255(256 台) |
| ホスト名 | app-server.example.com | DNS 解決されたホスト名 |
| localhost | localhost | ローカルホスト(127.0.0.1) |
設定変更後の反映
Shell(リスナーの再起動)
# sqlnet.ora を編集した後はリスナーを再起動する必要がある $ lsnrctl stop $ lsnrctl start # リスナーの状態を確認 $ lsnrctl status # データベースインスタンスの再起動は不要 # (sqlnet.ora はリスナーが接続ごとに読み込む)
設定変更前のテスト手順
(1) 別ターミナルを開いておく(締め出し時の復旧用)
(2) sqlnet.ora を編集
(3) リスナーを再起動
(4) 許可した IP からの接続テスト:
(5) 拒否すべき IP からの接続テスト(拒否されることを確認)
(6) 問題があれば sqlnet.ora を元に戻してリスナー再起動
(1) 別ターミナルを開いておく(締め出し時の復旧用)
(2) sqlnet.ora を編集
(3) リスナーを再起動
(4) 許可した IP からの接続テスト:
sqlplus hr/password@orcl(5) 拒否すべき IP からの接続テスト(拒否されることを確認)
(6) 問題があれば sqlnet.ora を元に戻してリスナー再起動
INVITED_NODES と EXCLUDED_NODES の使い分け
| 方式 | 動作 | 適するケース |
|---|---|---|
| INVITED_NODES(ホワイトリスト) | リストの IP のみ許可。それ以外は全て拒否 | 許可する IP が少数で明確な場合(本番環境向け) |
| EXCLUDED_NODES(ブラックリスト) | リストの IP だけ拒否。それ以外は全て許可 | 拒否する IP が少数の場合(開発環境でのテスト等) |
両方を同時に設定した場合
INVITED_NODES と EXCLUDED_NODES を同時に設定した場合、INVITED_NODES が優先されます。INVITED_NODES に含まれている IP は EXCLUDED_NODES に含まれていても接続可能です。混乱を避けるため、どちらか一方だけを設定することを推奨します。
INVITED_NODES と EXCLUDED_NODES を同時に設定した場合、INVITED_NODES が優先されます。INVITED_NODES に含まれている IP は EXCLUDED_NODES に含まれていても接続可能です。混乱を避けるため、どちらか一方だけを設定することを推奨します。
ログオントリガーによる DB レベルの IP 制限
sqlnet.ora はリスナーレベルの制限で全ユーザーに一律適用されますが、ログオントリガーならユーザーごとに異なる IP 制限を設定できます。
SQL(ユーザー別 IP 制限トリガー)
CREATE OR REPLACE TRIGGER trg_ip_restrict
AFTER LOGON ON DATABASE
DECLARE
v_ip VARCHAR2(100);
BEGIN
-- SYS / SYSTEM は制限しない
IF USER IN ('SYS', 'SYSTEM') THEN RETURN; END IF;
v_ip := SYS_CONTEXT('USERENV', 'IP_ADDRESS');
-- 管理者ユーザー: 特定 IP のみ許可
IF USER = 'ADMIN_USER' THEN
IF v_ip NOT IN ('10.0.1.100', '10.0.1.101') THEN
RAISE_APPLICATION_ERROR(-20001,
'ADMIN_USER は許可されたIPからのみ接続可能です: ' || v_ip);
END IF;
END IF;
-- アプリユーザー: アプリサーバーからのみ許可
IF USER = 'APP_USER' THEN
IF v_ip NOT LIKE '10.0.2.%' THEN
RAISE_APPLICATION_ERROR(-20002,
'APP_USER はアプリサーバーからのみ接続可能です: ' || v_ip);
END IF;
END IF;
END;
/
SQL(許可 IP をテーブルで管理: 柔軟な方式)
-- 許可 IP テーブル
CREATE TABLE allowed_ips (
username VARCHAR2(30),
ip_pattern VARCHAR2(100),
description VARCHAR2(200)
);
INSERT INTO allowed_ips VALUES ('ADMIN_USER', '10.0.1.100', '管理端末');
INSERT INTO allowed_ips VALUES ('ADMIN_USER', '10.0.1.101', '管理端末2');
INSERT INTO allowed_ips VALUES ('APP_USER', '10.0.2.%', 'アプリサーバー群');
COMMIT;
-- トリガー(テーブル参照版)
CREATE OR REPLACE TRIGGER trg_ip_restrict_table
AFTER LOGON ON DATABASE
DECLARE
v_ip VARCHAR2(100);
v_count NUMBER;
BEGIN
IF USER IN ('SYS', 'SYSTEM') THEN RETURN; END IF;
v_ip := SYS_CONTEXT('USERENV', 'IP_ADDRESS');
SELECT COUNT(*) INTO v_count FROM allowed_ips
WHERE username = USER AND v_ip LIKE ip_pattern;
IF v_count = 0 THEN
-- allowed_ips に登録がないユーザーは制限なし
SELECT COUNT(*) INTO v_count FROM allowed_ips WHERE username = USER;
IF v_count > 0 THEN
RAISE_APPLICATION_ERROR(-20003,
USER || ' はIPアドレス ' || v_ip || ' からの接続が許可されていません');
END IF;
END IF;
END;
/
テーブル管理方式のメリット
・IP の追加/変更がトリガーの再作成なしで可能(INSERT / UPDATE だけ)
・ユーザーごとに複数の IP パターンを柔軟に設定
・allowed_ips テーブルに未登録のユーザーは制限なし(全 IP 許可)
・IP の追加/変更がトリガーの再作成なしで可能(INSERT / UPDATE だけ)
・ユーザーごとに複数の IP パターンを柔軟に設定
・allowed_ips テーブルに未登録のユーザーは制限なし(全 IP 許可)
ログオントリガーの詳細は「ユーザーごとに接続制限を設定する方法」も参照してください。
OS ファイアウォールでの制限
Shell(Linux: firewalld)
# Oracle リスナーポート 1521 を特定 IP のみに開放
# (1) デフォルトで 1521 をブロック
firewall-cmd --permanent --remove-port=1521/tcp
# (2) 許可 IP からの 1521 のみ開放
firewall-cmd --permanent --add-rich-rule='
rule family=ipv4 source address=10.0.1.0/24 port port=1521 protocol=tcp accept'
firewall-cmd --permanent --add-rich-rule='
rule family=ipv4 source address=192.168.1.50 port port=1521 protocol=tcp accept'
# (3) 反映
firewall-cmd --reload
Shell(Linux: iptables)
# 特定 IP のみ 1521 を許可 iptables -A INPUT -p tcp --dport 1521 -s 10.0.1.0/24 -j ACCEPT iptables -A INPUT -p tcp --dport 1521 -s 192.168.1.50 -j ACCEPT iptables -A INPUT -p tcp --dport 1521 -j DROP # 設定の永続化 service iptables save
Shell(Windows: netsh)
# Windows ファイアウォールで 1521 を特定 IP のみに許可 netsh advfirewall firewall add rule name="Oracle 1521" dir=in action=allow protocol=tcp localport=1521 remoteip=10.0.1.0/24,192.168.1.50
| OS レイヤー | メリット | デメリット |
|---|---|---|
| OS ファイアウォール | Oracle に到達する前にブロック。最も堅牢 | Oracle のユーザーごとの細かい制御は不可 |
| sqlnet.ora | Oracle リスナーレベルで制御。OS 設定権限不要 | リスナー再起動が必要。ユーザー別制御は不可 |
| ログオントリガー | ユーザーごとに異なる IP を許可 / 拒否 | DB 接続後のチェック(TCP 接続自体は通る) |
設定変更後のテスト
Shell(接続テスト)
# 許可された IP から接続テスト sqlplus hr/password@//db-server:1521/orcl # → 接続成功すれば OK # 拒否されるべき IP から接続テスト sqlplus hr/password@//db-server:1521/orcl # → ORA-12537: TNS:connection closed # → ORA-12170: TNS:Connect timeout occurred # リスナーログで拒否を確認 # tail -f $ORACLE_BASE/diag/tnslsnr/*/listener/alert/log.xml
SQL(DB レベルの接続元 IP を確認)
-- 現在接続中のセッションの IP アドレスを確認
SELECT sid, serial#, username,
SYS_CONTEXT('USERENV', 'IP_ADDRESS') AS client_ip,
SYS_CONTEXT('USERENV', 'HOST') AS client_host
FROM v$session
WHERE username IS NOT NULL
ORDER BY username;
自分自身を締め出さないための安全策
| # | 安全策 |
|---|---|
| 1 | 別ターミナルを開いたまま設定を変更する(締め出し時に元に戻せるように) |
| 2 | INVITED_NODES に localhost と 127.0.0.1 を必ず含める |
| 3 | sqlnet.ora 編集前にバックアップを取る: cp sqlnet.ora sqlnet.ora.bak |
| 4 | 変更後すぐに接続テストを行い、問題があればバックアップから戻す |
| 5 | OS レベルでは sqlplus / as sysdba(OS 認証)で常にログイン可能にしておく |
最悪の場合の復旧手順
sqlnet.ora の設定ミスで全 IP からの接続がブロックされた場合:
(1) DB サーバーにコンソールまたは SSH でログイン
(2) sqlnet.ora のバックアップを戻す:
(3) リスナーを再起動:
sqlnet.ora の設定ミスで全 IP からの接続がブロックされた場合:
(1) DB サーバーにコンソールまたは SSH でログイン
(2) sqlnet.ora のバックアップを戻す:
cp sqlnet.ora.bak sqlnet.ora(3) リスナーを再起動:
lsnrctl stop; lsnrctl startsqlplus / as sysdba(OS 認証)は sqlnet.ora の影響を受けないため、DB の操作は可能です。実務パターン集
パターン(1): 本番 DB を社内ネットワークのみに制限
sqlnet.ora
TCP.VALIDNODE_CHECKING = YES TCP.INVITED_NODES = (10.0.0.0/8, 192.168.0.0/16, localhost, 127.0.0.1)
パターン(2): アプリサーバー + DBA 端末のみ許可
sqlnet.ora
TCP.VALIDNODE_CHECKING = YES
TCP.INVITED_NODES = (
10.0.2.10, # アプリサーバー1
10.0.2.11, # アプリサーバー2
10.0.1.50, # DBA 端末
localhost,
127.0.0.1
)
パターン(3): 開発環境で特定の不正 IP だけブロック
sqlnet.ora
TCP.VALIDNODE_CHECKING = YES TCP.EXCLUDED_NODES = (192.168.100.50, 10.99.*)
パターン(4): sqlnet.ora + トリガーの多層防御
設定例
# --- sqlnet.ora: 社内ネットワークのみ許可 ---
TCP.VALIDNODE_CHECKING = YES
TCP.INVITED_NODES = (10.0.0.0/8, localhost, 127.0.0.1)
# --- ログオントリガー: DBA ユーザーはさらに端末を限定 ---
# CREATE OR REPLACE TRIGGER trg_ip_restrict ...
# IF USER = 'DBA_USER' AND v_ip NOT IN ('10.0.1.50') THEN ...
よくある質問
Qsqlnet.ora の変更にデータベースの再起動は必要ですか?
A不要です。sqlnet.ora はリスナーが接続ごとに読み込むため、リスナーの再起動だけで反映されます(
lsnrctl stop; lsnrctl start)。データベースインスタンスの再起動は不要です。QINVITED_NODES と EXCLUDED_NODES を同時に設定するとどうなりますか?
AINVITED_NODES が優先されます。INVITED_NODES に含まれている IP は EXCLUDED_NODES に含まれていても接続可能です。混乱を避けるためどちらか一方だけを設定することを推奨します。
Qsqlplus / as sysdba は IP 制限の影響を受けますか?
A
sqlplus / as sysdba(OS 認証)はTCP 接続を経由しないため、sqlnet.ora の IP 制限の影響を受けません。設定ミスで全 IP がブロックされても、サーバー上でのローカル接続は可能です。Qログオントリガーで IP が NULL になることがあります
Aサーバー上でのローカル接続(
sqlplus / as sysdba)の場合、SYS_CONTEXT('USERENV', 'IP_ADDRESS') は NULL を返すことがあります。トリガー内で NULL のケースを考慮してください(NULL なら制限なしとするのが安全です)。Qワイルドカード(*)と CIDR 表記(/24)はどちらを使うべきですか?
Aどちらも機能しますが、CIDR 表記の方が正確です。
10.0.2.* は 10.0.2.0/24 と同等ですが、/16(10.0.0.0/16)のような広い範囲はワイルドカードでは 10.0.* と書く必要があり、CIDR の方が明確です。QOS ファイアウォールと sqlnet.ora のどちらで制限すべきですか?
A両方で制限するのがベストです。OS ファイアウォールは Oracle に到達する前にブロックするため最も堅牢です。sqlnet.ora は OS の設定権限がなくても DBA だけで設定できるメリットがあります。
まとめ
IP アクセス制限の要点をまとめます。
| やりたいこと | 方法 |
|---|---|
| 特定 IP のみ接続許可(リスナーレベル) | sqlnet.ora: TCP.VALIDNODE_CHECKING=YES + TCP.INVITED_NODES |
| 特定 IP だけ拒否 | sqlnet.ora: TCP.VALIDNODE_CHECKING=YES + TCP.EXCLUDED_NODES |
| ユーザーごとに IP を制限 | AFTER LOGON ON DATABASE トリガー + SYS_CONTEXT(‘USERENV’,’IP_ADDRESS’) |
| ネットワークレベルでポートをブロック | OS ファイアウォール(firewalld / iptables / Windows FW) |
| 多層防御(最も安全) | OS ファイアウォール + sqlnet.ora + ログオントリガー |
| 設定変更の反映 | lsnrctl stop; lsnrctl start(DB 再起動は不要) |
リスナー設定の詳細は「リスナー設定完全解説」、ユーザーごとの接続制限は「ユーザーごとに接続制限を設定する方法」も併せて参照してください。

