The following is a basic set of hardening guidelines for an Oracle 11g database along with some scripts you may find useful. This list is by no means complete. It does not cover file permissions, authentication controls and user profiles, encryption, grants or auditing but it is a good place to start.
Or perhaps takes Slavic's advice from his comment on this post and start with Oracle's Checklist for Database Security. It gives a broader, though perhaps less detailed view, and covers some of the topics I have left out (for now). Also check out Slavik's Musings on Database Security Blog.
- Put the database server behind a firewall. See prior post Wall It Off! for a discussion of the importance of a firewall, even for trusted users on your Intranet.
- Apply latest security patches for OS and harden the operating system.
- Install only the components needed. When installing the Oracle software, Spatial, OLAP, Data Mining, and Real Application Testing are all installed by default. Change the default behavior if you do not need these components. The MDSYS schema used by Spatial has been the target of security vulnerabilities in the past.
- 11g defaults to installing Advanced Security; this is a default that should be accepted assuming you have the license.
- Change the default name of the Listener (LISTENER) as well as the default port (1521).
- Do not install the sample schemas which are installed by default.
- When running the Database Configuration Assistant, select the Custom option so that you have the ability to de-select any unneeded components.
- Do take the default security settings, new for 11g, that enable auditing and a more hardened default profile. This setting also revokes CREATE EXTERNAL JOB from PUBLIC, sets 07_DICTIONARY_ACCESSIBILITY and REMOTE_OS_ROLES to FALSE as well as setting values for PASSWORD_GRACE_TIME, PASSWORD_LOCK_TIME and PASSWORD_LIFE_TIME to 7, 1, and 180 respectively rather than their previous default of UNLIMITED. This is a great move by Oracle.
- More good news. With 11g, a new initialization parameter called SEC_RETURN_SERVER_RELEASE_BANNER is available that controls the display of Oracle version information when clients connect to the database. It even defaults to FALSE (do not display), another good move by Oracle.
- Even more good news. With 11g, a new initialization parameter called SEC_CASE_SENSITIVE_LOGON is available to allow case sensitive passwords. It even defaults to the TRUE setting, meaning case sensitivity is supported. This can greatly increase password complexity and make it harder to use brute force attacks to guess passwords. Make use of this new feature when setting passwords.
- Exit the installer. Prior versions of Oracle left encrypted passwords in the install logs which could be easily decrypted by hackers. 11g appears to do a better job of this, instead displaying XXXXXXX or *********** . However, I still consider it a best practice to change passwords at the command line rather than through a tool. Make sure to use the "password <username>" syntax rather than the "alter user <username> identified by <password>" syntax since the former encrypts the password over the network and the later does not (at least in prior versions).
- Change the default passwords for all the locked accounts. These passwords can be made very , very strong since you will never use them.
- Also change the passwords of SYS and SYSTEM. Again this is just a precaution in case the installer left a remnant of the password you entered during the installation.
- If you configured Enterprise Manager (OEM) then also change the SYSMAN and DBSNMP account passwords using the appropriate procedure for those accounts in order not to break your OEM installation.
- Next you'll want to scan for default or weak passwords. I used to maintain my own script for this but now I rely on Alexander Kornbrust's, founder of Red Database Security GmbH . This is the best tool I've found and Alexander makes it freely available at: Oracle Password Checker (Cracker) .
- With 11g, Oracle also supplies a DBA_USERS_WITH_DEFPWD view. Selecting * from this view will return USERNAMEs with default passwords. This is nice to have but I still recommend Alexander's script instead since it also checks for weak passwords.
- You may be asking why all this checking for default and weak passwords when 11g does a good job of this? First, you may be upgrading from a previous, less secure version and have some old defaults. Second, DBAs are not infallible and sometimes create weak passwords. Scan regularly!
- Next we'll check for demo accounts. If you've followed the above instructions you should have none but it you are upgrading an existing database or forgot to change the default behavior of the installer, now is the time to check. I use Randy Giefer's Demo Account Check SQL Script which you can download here. Simply run the script and drop any demo accounts it finds.
- Next we need to harden the database listener. Oracle created an EXTPROC entry in your listener.ora configuration file whether you needed one or not. If you do not need to make external procedure calls from the database then the EXTPROC listener is not needed and should be removed. External procedure calls can give an attacker access to your operating system from within the database. Removing this capability eliminates this attack vector.The entry will look something like this: (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC<your-non-default-listener-port>)) . Simply backup your current listener.ora, remove the above line, and bounce the listener.
- Next you'll want to set administration restrictions on your listener. This will prevent the use of the SET command and require any listener configuration changes to be done by a user with write permissions on the listener.ora file. Simply save a backup of the listener.ora file, add the following line: ADMIN_RESTRICTIONS_LISTENER_<your-non-default-listener-name>=ON and then bounce the listener.
- Listener logging is turned on be default; however, it is generally a best practice to explicitly set values, even if it is a default. To explicitly set this parameter, save a backup of the listener.ora file, add the following line: LOGGING_LISTENER_<your-non-default-listener-name>=ON and then bounce the listener.
- The CIS benchmark recommends setting INBOUND_CONNECTION_TIMEOUT. This parameter specifies the time, in seconds, that a client must complete its connection attempt after the initial network connection has been acknowledged. The recommendation is to set it to the lowest value possible where none of your client connections are timing out. By default this parameter is not set. To set this parameter, save a backup of the listener.ora file, add the following line: INBOUND_CONNECTION_TIMEOUT_<your-non-default-listener-name> n where n is the number of seconds in which the client must complete its connection, and then bounce the listener.
- The CIS benchmark recommends setting SQLNET.INBOUND_CONNECTION_TIMEOUT. This parameter is similar to INBOUND_CONNECTION_TIMEOUT but it also includes the time for the initial network connection. Therefore Oracle and CIS recommend setting this value slightly higher than the INBOUND_CONNECTION_TIMEOUT value. By default this parameter is not set. To set this parameter, save a backup of the sqlnet.ora file, add the following line: SQLNET.INBOUND_CONNECTION_TIMEOUT n where n is slightly higher than the value for INBOUND_CONNECTION_TIMEOUT, and then bounce the listener.
- SQLNET.EXPIRE_TIME is an interesting parameter with multiple purposes. The original purpose was dead connection detection, that is, to detect abnormally terminated client-side connections and terminate the corresponding process on the server side. So if a client kills its connection and this parameter is not set, the server will indefinitely keep the server-side process active thus using valuable server resources for no good purpose. Setting this parameter to 10 will result in a probe being initiated every 10 minutes from the server to the client to see if the client connection has terminated and if so closing the server-side process. The other use for this parameter has developed out of the contrary goals of modern connection pooling (especially for J2EE apps) and firewall technology. Establishing a database connection is a relatively expensive and slow process from an application perspective. Connection pools resolve the problem by keeping open some set minimum number of connections, even when idle, such that connections are normally available to the application. This usually means you'll have at least some idle connections at all times. Enter firewalls, which are generally configured to tear down idle connections (without notifying the client) after some set period of inactivity. When a firewall does this tear down, the client has no idea and assumes it has a good database connection; however, when the pool tries to reuse a torn down connection it get an error. Even if the application is well written and handles the exception, it will still take considerable time to attempt to reuse the connection, get the error, handle the error and retry the connection. If the firewall has torn down multiple connections, which is typically the case, this whole process my be repeated several times for multiple users causing sever performance problems. Setting SQLNET.EXPIRE_TIME causes the probe to be sent from server to client even on idle but active connections. This probe represents activity to the firewall and it therefore no longer considers the connection to be idle and therefore will not tear it down. So if you use connection pools and have a firewall between your app and database tier, set SQLNET.EXPIRE_TIME to no more than half the value of you firewall's idle connection timeout in minutes.
- Block access to your database listener by IP address. Even if your firewall is compromised, you'll have another layer of security protecting the listener. To enable this feature, backup your sqlnet.ora file, then add the following lines:
- tcp.validnode_checking = yes
- tcp.invited_nodes = (hostname1, hostname2, ... , hostnameN)
- You can specify a list of hostnames or IP addresses. If you use hostnames, they must be resolvable to an IP address or the listener will not start.
- Unfortunately, the node list does not support partial IP addresses or subnet masks in the manner of an Apache configuration. You must specify a full IP address or a resolvable hostname.
- You can use tcp.excluded_nodes instead of tcp.invited_nodes; however, the two are mutually exclusive. If you specify both, the excluded nodes will be ignored.
- 11g comes with a more secure listener out of the box. You can only stop the listener as the local OS account that started the listener. Therefore, it is now actually more secure to NOT set a listener password since setting one enables remote administration. Scanners will likely ding you on this but it is the appropriate practice for 11g.
- By default, Oracle registers an XPT service. If you are not using DataGurad you should remove this service by running the following as SYS:
alter system set "__dg_broker_service_names" = '' scope=spfile;- Note the parameter starts with two underscores.
- Then bounce the database
- lsnrctl status should now no longer show the XPT service
- This one is a little off topic but useful to know. If you have an existing database with XML DB installed but you do not need it, you can disable the functionality and reduce your attack vectors by running the following as SYS: alter system reset dispatchers scope=spfile sid='*';
- Next you'll want to explicitly set the hidden parameter _trace_files_public to false. To do this:
- create pfile from spfile;
- Add *._trace_files_public=false to the pfile
- shutdown immediate
- startup pfile='<full-path-to-pfile>'
- create spfile from pfile;
- shutdown immediate
- startup
- Finally, download, read and run the basic CIS Hardening Script. Make sure to read the comments in the script to make sure the settings as appropriate for your environment. The database will need to be bounced for these changes to take effect. This script sets:
- GLOBAL_NAMES=TRUE
- OS_AUTHENT_PREFIX TO THE NULL STRING
- SQL92_SECURITY=TRUE
- AUDIT_SYS_OPERATIONS=TRUE