v$active_session_history中查不到client_ip字段,因其仅记录会话行为(如等待事件、sql_id),不采集tcp层ip信息;真实ip需通过session_id/session_serial#关联v$session_connect_info、unified_audit_trail或监听日志获取。

V$ACTIVE_SESSION_HISTORY 里查不到 CLIENT_IP 字段,硬写 WHERE client_ip = 'x.x.x.x' 必然报错——这不是权限或视图没刷新的问题,是字段根本不存在。
为什么ASH查不到客户端IP
Oracle 的 ASH 只记录会话“在做什么”:等什么事件、执行哪条 SQL_ID、被谁阻塞。它不记录 TCP 层信息,CLIENT_IP 不在采集范围。很多 DBA 直接 SELECT * FROM v$active_session_history 然后 Ctrl+F 搜 IP,结果一无所获,浪费大量时间。
真正含 IP 的源头在三处:V$SESSION_CONNECT_INFO(部分线索)、UNIFIED_AUDIT_TRAIL(需审计启用)、监听日志 listener.log(最直接)。
用SESSION_ID+SESSION_SERIAL#反向查IP的实操路径
先从 ASH 锁定可疑会话(比如高频失败登录或长空闲),再通过 SESSION_ID 和 SESSION_SERIAL# 关联其他视图补全 IP:
- 查 ASH 中近期密集出现登录等待的样本:
SELECT SESSION_ID, SESSION_SERIAL#, SAMPLE_TIME, EVENT, MODULE FROM V$ACTIVE_SESSION_HISTORY WHERE EVENT LIKE 'SQL*Net message from client' AND (MODULE IS NULL OR MODULE LIKE '%login%') AND SAMPLE_TIME > SYSDATE - 5/1440 ORDER BY SAMPLE_TIME DESC;
- 拿返回的
SESSION_ID/SESSION_SERIAL#去查V$SESSION_CONNECT_INFO:SELECT SID, SERIAL#, NETWORK_SERVICE_BANNER, CLIENT_CHARSET FROM V$SESSION_CONNECT_INFO WHERE SID = &sid AND SERIAL# = &serial;
注意:NETWORK_SERVICE_BANNER里可能含主机名或协议版本,但不保证有 IP - 更准的方式是查统一审计日志:
SELECT CLIENT_IP, DBUSERNAME, RETURN_CODE, TIMESTAMP FROM UNIFIED_AUDIT_TRAIL WHERE AUDIT_TYPE = 'DATABASE LOGON' AND RETURN_CODE != 0 AND TIMESTAMP > SYSDATE - 1/24 ORDER BY TIMESTAMP DESC;
前提:已启用AUDIT POLICY ORA_SECURECONFIG,否则该视图为空
监听日志比ASH更快定位真实IP
对数据库零侵入,且能拿到原始连接时的 HOST 和 PORT,比查视图更可靠:
- 先从
v$session获取目标会话的PORT和LOGON_TIME:SELECT sid, serial#, username, port, machine, logon_time FROM v$session WHERE sid = 123;
- 查监听日志路径:
lsnrctl status,通常在$ORACLE_HOME/network/log/listener.log - 在日志中搜索对应
PORT和相近时间戳的记录,关键字段是:(ADDRESS=(PROTOCOL=tcp)(HOST=xxx.xxx.xx.xx)(PORT=57918)) - 注意时间格式要对齐:日志用本地时区,数据库
SYSDATE也是本地时区,别用 UTC 时间去匹配
触发器方案:需要提前部署,但能永久捕获
如果必须在数据库侧留存 IP 记录,且无法启用统一审计,可用触发器落库,但要注意生产风险:
- 创建表:
CREATE TABLE login_failures ( username VARCHAR2(30), ip_address VARCHAR2(15), login_time TIMESTAMP, error_code NUMBER );
- 创建触发器(仅捕获 ORA-01017):
CREATE OR REPLACE TRIGGER log_login_failures AFTER SERVERERROR ON DATABASE BEGIN IF (IS_SERVERERROR(1017)) THEN INSERT INTO login_failures (username, ip_address, login_time, error_code) VALUES (SYS_CONTEXT('USERENV', 'SESSION_USER'), SYS_CONTEXT('USERENV', 'IP_ADDRESS'), SYSTIMESTAMP, SQLCODE); END IF; END; / - 关键限制:
SYS_CONTEXT('USERENV', 'IP_ADDRESS')在登录失败时不一定总能取到值,尤其 JDBC Thin Client 或代理后场景下常为空;触发器本身有性能开销,上线前务必压测
真正能稳定拿到 IP 的路径只有两条:监听日志(事后回溯快)和统一审计(实时性强但需提前配置)。ASH 只是起点,不是终点——它帮你圈出“谁可疑”,但 IP 得靠别的视图或日志来填空。











