How to Prevent DBA User From Logining Database Without Password

on

我们知道如果某个操作系统用户属于dba组,那么登录了这个用户之后,不再需要任何密码就能以SYS用户登录到数据库中,在产品环境中,这无疑是一个严重的安全漏洞。

kamus@desktop:~$ whoami
kamus
kamus@desktop:~$ sqlplus / as sysdba

SQL*Plus: Release 11.1.0.6.0 - Production on Sun Apr 5 17:56:58 2009

Copyright (c) 1982, 2007, Oracle.  All rights reserved.

Connected to an idle instance.

SQL> show user
USER is "SYS"
SQL> exit
Disconnected
kamus@desktop:~$ sqlplus nouser/nopassword as sysdba

SQL*Plus: Release 11.1.0.6.0 - Production on Sun Apr 5 17:37:42 2009

Copyright (c) 1982, 2007, Oracle.  All rights reserved.

Connected to an idle instance.

SQL> show user
USER is "SYS"
SQL>  

正如上面的演示,我们轻松以SYS身份登录进了数据库,无须给任何用户名密码,甚至是随便给一个毫不存在的用户和密码也可以。

如何防止这样的问题?

首先,我们可以利用oracle自身提供的sqlnet.ora文件中的参数sqlnet.authentication_services。在$ORACLE_HOME/network/admin/sqlnet.ora文件中添加如下行:
sqlnet.authentication_services=(NONE)

再次尝试不提供用户密码登录sqlplus,将遇到ORA-01031错误。

kamus@desktop:~$ sqlplus / as sysdba

SQL*Plus: Release 11.1.0.6.0 - Production on Sun Apr 5 18:05:07 2009

Copyright (c) 1982, 2007, Oracle.  All rights reserved.

ERROR:
ORA-01031: insufficient privileges


Enter user-name: ^C
kamus@desktop:~$ sqlplus sys/oracle as sysdba

SQL*Plus: Release 11.1.0.6.0 - Production on Sun Apr 5 18:06:31 2009

Copyright (c) 1982, 2007, Oracle.  All rights reserved.

Connected to an idle instance.

SQL> 

更进一步,我们还可以让dba组的其他用户必须通过监听程序来连接数据库,这样内置于监听中的审计和跟踪功能就能得到更好的使用。

先来看一下如果不通过监听连接数据库的情况。继续上面的例子,在我们通过用户名密码成功登录数据库实例以后,查看一下操作系统级别的进程。

kamus@desktop:~$ ps -ef|grep sqlplus
kamus     6556  5409  0 18:06 pts/0    00:00:00 sqlplus            as sysdba
kamus     6561  5601  0 18:11 pts/2    00:00:00 grep sqlplus
kamus@desktop:~$ ps -ef|grep 6556 | grep -v grep
kamus     6556  5409  0 18:06 pts/0    00:00:00 sqlplus            as sysdba
oracle    6557  6556  0 18:06 ?        00:00:00 oracleorcl11g (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))

pid为6556的进程是user process,对应其的server process的pid是6557,这就是oracle使用的双层架构(Two-Task Architecture),任何用户进程(user process)不会跟数据库内存或者数据文件直接交互,而是通过一个对应的服务端进程(server process)来完成工作的。

我们可以注意到,6556进程的属主是kamus,因为是这个用户执行的sqlplus命令,但是6557进程的属主却是oracle,这是为什么呢?这归功于setuid。查看一下oracle可执行文件的权限。

kamus@desktop:~$ cd $ORACLE_HOME/bin
kamus@desktop:/u01/app/oracle/product/11.1.0/bin$ ls -l oracle
-rwsr-s--x 1 oracle oinstall 144792107 2009-01-05 14:01 oracle

owner的权限是rws,最后的s位表明在该执行文件上启用了setuid,具体含义就是不管是那个用户执行了该文件,该文件总是以属主的身份运行。那么如果我们取消掉s位,会出现什么情况呢?

kamus@desktop:/u01/app/oracle/product/11.1.0/network/admin$ cd
kamus@desktop:~$ su - oracle
Password: 
[orcl11g]@desktop[/home/oracle]$cd $ORACLE_HOME/bin
[orcl11g]@desktop[/u01/app/oracle/product/11.1.0/bin]$chmod u-s oracle
[orcl11g]@desktop[/u01/app/oracle/product/11.1.0/bin]$ls -l oracle
-rwxr-s--x 1 oracle oinstall 144792107 2009-01-05 14:01 oracle

再次尝试在kamus用户下登录sqlplus。碰到了ORA-09925错误。

kamus@desktop:~$ sqlplus sys/oracle as sysdba

SQL*Plus: Release 11.1.0.6.0 - Production on Sun Apr 5 18:26:16 2009

Copyright (c) 1982, 2007, Oracle.  All rights reserved.

ERROR:
ORA-09925: Unable to create audit trail file


Enter user-name: 

再检查一下后台进程。

kamus@desktop:~$ ps -ef|grep sqlplus|grep -v grep
kamus     6699  5601  0 18:26 pts/2    00:00:00 sqlplus            as sysdba
kamus@desktop:~$ ps -ef|grep 6699|grep -v grep
kamus     6699  5601  0 18:26 pts/2    00:00:00 sqlplus            as sysdba
kamus     6700  6699  0 18:26 ?        00:00:00 oracleorcl11g (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))

原因很清楚,当我们去掉了oracle可执行文件的s位以后,server process的属主成为了kamus,而不是之前的oracle。登录sqlplus需要记录一定的audit信息,这是由server process来完成的,但是因为现在属主是kamus,并没有权限在oracle软件的安装目录中写入任何信息,因此报ORA-09925错误。

更彻底一些,我们连server process都不允许在本地启动,去掉oracle可执行文件的其他用户执行权限,只保留属主的读写执行权限。

[orcl11g]@desktop[/u01/app/oracle/product/11.1.0/bin]$chmod 0700 oracle
[orcl11g]@desktop[/u01/app/oracle/product/11.1.0/bin]$ls -l oracle
-rwx------ 1 oracle oinstall 144792107 2009-01-05 14:01 oracle

再次尝试登录sqlplus,这次碰到了ORA-12546错误。

kamus@desktop:~$ sqlplus sys/oracle as sysdba

SQL*Plus: Release 11.1.0.6.0 - Production on Sun Apr 5 18:44:14 2009

Copyright (c) 1982, 2007, Oracle.  All rights reserved.

ERROR:
ORA-12546: TNS:permission denied


Enter user-name: 

检查后台进程,可以看到根本就没有启动成功的server process。

kamus@desktop:~$ ps -ef|grep sqlplus|grep -v grep
kamus     6916  5601  0 18:44 pts/2    00:00:00 sqlplus            as sysdba
kamus     6917  6916  0 18:44 ?        00:00:00 [sqlplus] 

在这种设置下,必须要通过监听才可以登录数据库。

首先,使用oracle用户登陆,启动数据库。取消掉oracle可执行文件的s位后,必须要登陆到该文件的属主用户下,才可以启动数据库。

[orcl11g]@desktop[/home/oracle]$sqlplus sys/oracle as sysdba

SQL*Plus: Release 11.1.0.6.0 - Production on Sun Apr 5 18:56:23 2009

Copyright (c) 1982, 2007, Oracle.  All rights reserved.

Connected to an idle instance.

SQL> startup
ORACLE instance started.

Total System Global Area  238530560 bytes
Fixed Size                  1299116 bytes
Variable Size             100666708 bytes
Database Buffers          134217728 bytes
Redo Buffers                2347008 bytes
Database mounted.
Database opened.
SQL> 

然后再登陆kamus用户,尝试登陆sqlplus。orcl11g是在tnsnames.ora文件中已经设置过的连接字串。

[orcl11g]@desktop[/home/kamus]$sqlplus sys/oracle@orcl11g as sysdba

SQL*Plus: Release 11.1.0.6.0 - Production on Sun Apr 5 18:57:16 2009

Copyright (c) 1982, 2007, Oracle.  All rights reserved.


Connected to:
Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production
With the Partitioning and Real Application Testing options

SQL> 

通过监听,可以正常连接数据库了。再检查一下后台进程的情况。

[orcl11g]@desktop[/home/kamus]$ps -ef|grep sqlplus|grep -v grep
oracle    7077  6966  0 18:56 pts/3    00:00:00 sqlplus            as sysdba
kamus     7156  7008  0 18:57 pts/5    00:00:00 sqlplus                    as sysdba
[orcl11g]@desktop[/home/kamus]$ps -ef|grep LOCAL|grep -v grep
oracle    7118  7077  1 18:56 ?        00:00:02 oracleorcl11g (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))
oracle    7172     1  0 18:57 ?        00:00:00 oracleorcl11g (LOCAL=NO) 

7077进程是我们使用oracle用户打开的sqlplus连接,对应的server process是7118,7156进程则是使用kamus用户打开的sqlplus连接,可以看到并没有父进程是7156的server process,只有一个7172的进程,它的父进程号是1。

[orcl11g]@desktop[/home/kamus]$ps -fp 1
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 17:10 ?        00:00:01 /sbin/init 

1是初始化进程,父进程为1代表这个进程是被fork出来的,这就是通过监听连接数据库的机制,user process联系监听,监听再fork一个server process用以应对客户端的请求。

至此,我们已经完成了对于数据库连接的基本安全性设置。

结论:通过下面的两种方法来完成数据库连接的安全保障。
1. 在sqlnet.ora文件中添加sqlnet.authentication_services=(NONE),用以保证必须要给出SYS用户密码才能登陆。
2. 设置oracle可执行文件的运行权限为0700,用以保证非oracle软件的属主必须要通过监听才可以连接数据库。

安全,并不仅仅是局限于数据库本身的,在本文的安全性设置中,它牵涉到数据库运行的机制以及操作系统的部分知识,当你的知识越全面,你就能想到越多的方法来完善整个系统的安全。当然,安全性的建设也远远不局限于技术层面,规章制度、人员素质、完善的审计流程都具有决定性的影响。

One Comment Add yours

  1. liang.xie says:

    这篇文章挺帅~~~

Leave a Reply to liang.xie Cancel reply

Your email address will not be published. Required fields are marked *