一、SQLPlus安全概述
1.1 为什么安全设置重要?
在CentOS服务器上运行Oracle数据库时,SQLPlus是主要的数据库访问工具。未经安全加固的SQLPlus环境可能面临以下风险:
- 未授权访问:弱密码或默认账户被攻击者利用
- 数据泄露:敏感数据通过SQL注入等方式被窃取
- 权限滥用:过度授权导致数据被恶意修改或删除
- 审计缺失:无法追踪用户操作,难以及时发现异常
1.2 安全策略概览
| 安全领域 | 核心措施 | 优先级 |
|---|---|---|
| 账户管理 | 强密码策略、最小权限原则 | 高 |
| 网络安全 | 防火墙、SSL/TLS加密 | 高 |
| SQL注入防护 | 参数化查询、输入验证 | 高 |
| 审计监控 | 操作日志、异常告警 | 中 |
| 文件权限 | 配置文件保护、日志加密 | 中 |
二、账户与权限安全
2.1 密码策略配置
-- 创建Profile并设置密码策略
CREATE PROFILE secure_profile LIMIT
FAILED_LOGIN_ATTEMPTS 5 -- 连续失败5次后锁定
PASSWORD_LOCK_TIME 1 -- 锁定1天
PASSWORD_LIFE_TIME 90 -- 密码90天有效
PASSWORD_REUSE_MAX 3 -- 密码至少换3次后才能重用
PASSWORD_REUSE_DELAY 30; -- 30天内不能重用旧密码
-- 将Profile分配给用户
ALTER USER scott PROFILE secure_profile;
-- 设置强密码(Oracle 12c+)
ALTER USER scott IDENTIFIED BY "Str0ngP@ssw0rd!";
-- 检查用户密码过期时间
SELECT username, profile, account_status, expiry_date
FROM dba_users
WHERE account_status = 'EXPIRED';
2.2 最小权限原则
-- 创建应用专用账户
CREATE USER app_user IDENTIFIED BY "AppP@ss123!"
DEFAULT TABLESPACE users
TEMPORARY TABLESPACE temp;
-- 按需授予权限(不要授予DBA)
GRANT CREATE SESSION TO app_user; -- 只允许连接
GRANT SELECT ON scott.emp TO app_user; -- 只读表emp
GRANT INSERT, UPDATE ON scott.orders TO app_user; -- 读写orders表
-- 撤销不必要的权限
REVOKE DBA FROM app_user;
REVOKE DELETE ANY TABLE FROM app_user;
-- 查看用户权限
SELECT * FROM dba_tab_privs WHERE grantee = 'APP_USER';
SELECT * FROM dba_sys_privs WHERE grantee = 'APP_USER';
2.3 角色管理
-- 创建应用角色
CREATE ROLE app_read_role;
CREATE ROLE app_write_role;
-- 配置角色权限
GRANT SELECT ON scott.emp TO app_read_role;
GRANT SELECT ON scott.dept TO app_read_role;
GRANT INSERT, UPDATE, DELETE ON scott.emp TO app_write_role;
-- 分配角色给用户
GRANT app_read_role TO app_user;
GRANT app_write_role TO app_admin;
-- 查看角色权限
SELECT * FROM dba_sys_privs WHERE grantee IN ('APP_READ_ROLE', 'APP_WRITE_ROLE');
三、网络访问安全
3.1 配置SSL/TLS加密
# 生成Oracle Wallet(证书存储)
mkdir -p /u01/app/oracle/wallet
orapki wallet create -wallet /u01/app/oracle/wallet -pwd "WalletPass123!" -auto_login_local
# 创建自签名证书
orapki wallet add -wallet /u01/app/oracle/wallet -dn "CN=dbserver.example.com" -keysize 2048 -validity 365 -self_signed -pwd "WalletPass123!"
# 导出证书
orapki wallet export -wallet /u01/app/oracle/wallet -dn "CN=dbserver.example.com" -cert /tmp/dbserver_cert.txt -pwd "WalletPass123!"
-- 配置SQLNet加密
-- 编辑 $ORACLE_HOME/network/admin/sqlnet.ora
ALTER SYSTEM SET sqlnet.encryption_server = REQUIRED SCOPE = BOTH;
ALTER SYSTEM SET sqlnet.encryption_types_server = (AES256, AES192, AES128) SCOPE = BOTH;
ALTER SYSTEM SET sqlnet.crypto_checksum_server = REQUIRED SCOPE = BOTH;
ALTER SYSTEM SET sqlnet.crypto_checksum_types_server = (SHA256, SHA1) SCOPE = BOTH;
3.2 防火墙配置
# 只允许特定IP访问Oracle端口
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port protocol="tcp" port="1521" accept'
# 拒绝其他所有访问
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" port protocol="tcp" port="1521" drop'
# 重载防火墙规则
firewall-cmd --reload
# 查看规则
firewall-cmd --list-rich-rules
3.3 监听器安全配置
# 编辑 $ORACLE_HOME/network/admin/listener.ora
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = dbserver.example.com)(PORT = 1521))
)
)
# 安全设置
ADMIN_RESTRICT_LISTENER = ON
SECURE_REGISTER_listener = (TCP)
# 重启监听器
lsnrctl stop
lsnrctl start
lsnrctl reload
四、SQL注入防护
4.1 参数化查询
-- 错误写法(容易SQL注入)
-- SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
-- 正确写法:使用绑定变量
SELECT * FROM users WHERE username = :username AND password = :password;
4.2 输入验证函数
-- 创建输入验证函数
CREATE OR REPLACE FUNCTION validate_input(
p_input VARCHAR2
) RETURN VARCHAR2 IS
v_result VARCHAR2(4000);
BEGIN
-- 移除危险字符
v_result := REGEXP_REPLACE(p_input, '(''|;|--|/*|*/|xp_|sp_)', '');
RETURN v_result;
END validate_input;
/
-- 在存储过程中使用
CREATE OR REPLACE PROCEDURE search_employee(
p_name IN VARCHAR2,
p_result OUT SYS_REFCURSOR
) AS
BEGIN
OPEN p_result FOR
SELECT * FROM employees
WHERE name = validate_input(p_name);
END search_employee;
/
4.3 最小权限运行存储过程
-- 以调用者权限运行(更安全)
CREATE OR REPLACE PROCEDURE search_employee(
p_name IN VARCHAR2,
p_result OUT SYS_REFCURSOR
) AUTHID CURRENT_USER IS
BEGIN
OPEN p_result FOR
SELECT * FROM employees WHERE name = p_name;
END search_employee;
/
-- 使用 DEFINER vs CURRENT_USER
-- DEFINER:以创建者权限运行(存在风险)
-- AUTHID CURRENT_USER:以调用者权限运行(更安全)
五、审计与监控
5.1 启用审计
-- 启用审计
ALTER SYSTEM SET audit_trail = DB, EXTENDED SCOPE = SPFILE;
-- 审计所有SQL操作
AUDIT ALL BY app_user BY SESSION;
AUDIT SELECT TABLE, INSERT TABLE, UPDATE TABLE, DELETE TABLE BY app_user;
-- 审计失败登录
AUDIT CREATE SESSION WHENEVER NOT SUCCESSFUL;
-- 审计特权操作
AUDIT EXECUTE ON DBMS_CDC_PUBLISH;
AUDIT EXECUTE ON DBMS_FLASHBACK;
5.2 查询审计日志
-- 查看审计记录
SELECT username,
timestamp,
action_name,
sql_text,
returncode
FROM dba_audit_trail
WHERE username = 'APP_USER'
ORDER BY timestamp DESC;
-- 统计异常操作
SELECT username, action_name, COUNT(*)
FROM dba_audit_trail
WHERE timestamp > SYSDATE - 7
GROUP BY username, action_name
HAVING COUNT(*) > 100;
-- 查看失败登录
SELECT username,
terminal,
timestamp,
returncode
FROM dba_audit_trail
WHERE action_name = 'LOGON'
AND returncode != 0
ORDER BY timestamp DESC;
5.3 实时监控脚本
#!/bin/bash
# /opt/scripts/monitor_sqlplus.sh
# SQLPlus操作实时监控脚本
# 监控可疑SQL
echo "检查最近1小时的异常查询..."
sqlplus / as sysdba << EOF
SELECT username, COUNT(*) as query_count
FROM v\$session s
JOIN v\$sqltext_with_newlines t ON s.sql_address = t.address
WHERE s.logon_time > SYSDATE - 1/24
GROUP BY username
HAVING COUNT(*) > 50
ORDER BY query_count DESC;
EOF
# 检查活跃会话
echo "检查活跃会话..."
sqlplus / as sysdba << EOF
SELECT s.username, s.program, s.status, s.sid, s.serial#
FROM v\$session s
WHERE s.status = 'ACTIVE'
AND s.username IS NOT NULL
ORDER BY s.logon_time;
EOF
六、文件与目录安全
6.1 配置文件权限
# 保护Oracle配置文件
chmod 600 $ORACLE_HOME/network/admin/sqlnet.ora
chmod 600 $ORACLE_HOME/network/admin/listener.ora
chmod 600 $ORACLE_HOME/network/admin/tnsnames.ora
chown oracle:oinstall $ORACLE_HOME/network/admin/*.ora
# 保护数据文件
chmod 600 /u01/app/oracle/oradata/*.dbf
chown oracle:oinstall /u01/app/oracle/oradata/*.dbf
# 保护备份文件
chmod 600 /backup/oracle/*.dmp
chown oracle:oinstall /backup/oracle/*.dmp
6.2 日志文件保护
# 压缩并加密审计日志
find /u01/app/oracle/admin/orcl/adump -name "*.aud" -mtime +30 -exec gzip {} \;
# 设置日志保留期限
find /u01/app/oracle/admin/orcl/adump -name "*.aud.gz" -mtime +180 -delete
# 保护alert日志
chmod 640 $ORACLE_HOME/diag/rdbms/orcl/orcl/trace/alert_orcl.log
6.3 环境变量安全
# 禁止在命令行中明文显示密码
# 使用Oracle Wallet替代密码
mkstore -wrl /u01/app/oracle/wallet -create
mkstore -wrl /u01/app/oracle/wallet -createCredential ORCL scott "Sc0ttP@ss!"
# 在sqlnet.ora中配置Wallet
WALLET_LOCATION = (SOURCE = (METHOD = FILE)(METHOD_DATA = (DIRECTORY = /u01/app/oracle/wallet)))
SQLNET.WALLET_OVERRIDE = TRUE
# 使用Wallet连接(无需明文密码)
sqlplus /@ORCL
七、高级安全配置
7.1 Oracle Database Vault
-- 启用Database Vault(需单独安装)
EXEC DBMS_MACADM.ENABLE_DATABASE_VAULT;
-- 创建安全区域
BEGIN
DBMS_MACADM.CREATE_REALM(
realm_name => 'HR Data Realm',
description => 'Protect HR sensitive data',
enabled => DBMS_MACUTL.G_YES,
audit_options => DBMS_MACUTL.G_REALM_AUDIT_FAIL);
END;
/
-- 添加保护对象到区域
BEGIN
DBMS_MACADM.ADD_OBJECT_TO_REALM(
realm_name => 'HR Data Realm',
object_type => 'TABLE',
object_owner => 'HR',
object_name => 'EMPLOYEES');
END;
/
-- 创建命令规则
BEGIN
DBMS_MACADM.CREATE_COMMAND_RULE(
command => 'DROP TABLE',
rule_set_name => 'Deploy Table',
object_owner => '%',
object_name => '%');
END;
/
7.2 数据脱敏
-- 创建数据脱敏策略
BEGIN
DBMS_REDACT.ADD_POLICY(
object_schema => 'HR',
object_name => 'EMPLOYEES',
column_name => 'SALARY',
policy_name => 'MASK_SALARY',
function_type => DBMS_REDACT.FULL,
expression => 'SYS_CONTEXT(''USERENV'',''SESSION_USER'') NOT IN (''HR_ADMIN'')');
END;
/
-- 验证脱敏效果
-- 以普通用户查看(看到的是脱敏数据)
SELECT first_name, last_name, salary FROM hr.employees;
-- 以管理员查看(看到真实数据)
SELECT first_name, last_name, salary FROM hr.employees WHERE SYS_CONTEXT('USERENV','SESSION_USER') = 'HR_ADMIN';
7.3 Transparent Data Encryption (TDE)
-- 创建钱包
ALTER SYSTEM SET ENCRYPTION WALLET OPEN IDENTIFIED BY "WalletPass123!";
-- 创建加密表空间
CREATE TABLESPACE encrypted_ts
DATAFILE '/u01/app/oracle/oradata/encrypted_ts01.dbf'
SIZE 100M ENCRYPTION USING 'AES256'
DEFAULT STORAGE (ENCRYPT);
-- 在加密表空间中创建表(数据自动加密)
CREATE TABLE sensitive_data (
id NUMBER,
data VARCHAR2(4000)
) TABLESPACE encrypted_ts;
-- 加密现有列
ALTER TABLE hr.employees ADD (salary_encrypted VARCHAR2(4000) ENCRYPT);
UPDATE hr.employees SET salary_encrypted = salary;
ALTER TABLE hr.employees DROP COLUMN salary;
ALTER TABLE hr.employees RENAME COLUMN salary_encrypted TO salary;
八、安全检查清单
8.1 账户安全检查
| 检查项 | 检查方法 | 标准 |
|---|---|---|
| 密码复杂度 | 检查dba_profiles | FAILED_LOGIN_ATTEMPTS >= 3 |
| 默认账户 | 检查dba_users | 无EXPIRED状态的默认账户 |
| 最小权限 | 检查dba_sys_privs | 无过度授权的DBA |
| 角色分离 | 检查角色成员 | 无用户同时拥有读写权限 |
8.2 网络安全检查
| 检查项 | 检查方法 | 标准 |
|---|---|---|
| 加密通信 | 检查sqlnet.ora | encryption_server = REQUIRED |
| 防火墙 | 检查firewall-cmd | 只开放必要端口 |
| 监听器安全 | 检查listener.ora | ADMIN_RESTRICT_LISTENER = ON |
8.3 审计检查
| 检查项 | 检查方法 | 标准 |
|---|---|---|
| 审计启用 | 检查audit_trail | audit_trail = DB, EXTENDED |
| 日志保留 | 检查adump目录 | 日志保留至少90天 |
| 异常告警 | 检查监控脚本 | 有自动告警机制 |
九、常见问题与解决方案
Q1:用户密码过期怎么办?
A:
-- 查看密码过期用户
SELECT username, expiry_date FROM dba_users WHERE expiry_date < SYSDATE;
-- 重置密码
ALTER USER scott IDENTIFIED BY "NewStr0ngP@ss!";
-- 设置为不过期
ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME UNLIMITED;
Q2:如何防止SQL注入?
A:
1. 使用参数化查询,禁止拼接SQL
2. 启用Oracle Audit Vault监控可疑查询
3. 定期扫描代码中的SQL注入漏洞
Q3:审计日志占用大量空间?
A:
-- 启用统一审计日志压缩
BEGIN
DBMS_AUDIT_MGMT.SET_AUDIT_TRAIL_PROPERTY(
DBMS_AUDIT_MGMT.AUDIT_TRAIL_UNIFIED,
DBMS_AUDIT_MGMT.AUDIT_TRAIL_PROPERTY_RETENTION,
90); -- 保留90天
END;
/
-- 清理旧审计记录
BEGIN
DBMS_AUDIT_MGMT.CLEAN_AUDIT_TRAIL(
audit_trail_type => DBMS_AUDIT_MGMT.AUDIT_TRAIL_UNIFIED,
use_last_arch_timestamp => TRUE);
END;
/
Q4:如何审计SELECT操作?
A:
-- 启用细粒度审计(FGA)审计SELECT
BEGIN
DBMS_FGA.ADD_POLICY(
object_schema => 'HR',
object_name => 'EMPLOYEES',
policy_name => 'AUDIT_EMP_SELECT',
audit_condition => NULL,
statement_types => 'SELECT');
END;
/
-- 查询FGA审计记录
SELECT timestamp, db_user, object_schema, object_name, sql_text
FROM dba_fga_audit_trail
WHERE object_name = 'EMPLOYEES';
十、总结
在CentOS上配置SQLPlus安全需要从多个维度入手:
- 账户安全:强密码、最小权限、角色分离
- 网络安全:SSL/TLS加密、防火墙、监听器加固
- SQL注入防护:参数化查询、输入验证、权限控制
- 审计监控:启用审计、实时监控、异常告警
- 文件安全:配置文件保护、日志加密、环境变量隐藏
- 高级安全:Database Vault、数据脱敏、TDE加密
核心要点:
– 遵循最小权限原则,避免过度授权
– 使用SSL/TLS加密所有网络通信
– 始终使用参数化查询,防止SQL注入
– 启用审计并定期检查异常操作
– 定期更新安全策略,应对新型威胁
通过本文的指南,你可以建立完善的SQLPlus安全防护体系,确保Oracle数据库在CentOS环境中的安全运行。
注:本文基于CentOS 7/8和Oracle 19c/21c编写,具体配置可能因版本差异而略有不同。