Databases

Secure Oracle Database with cnspec

Scan Oracle databases, users, roles, and profiles against security and compliance best practices with cnspec.

Scan your Oracle databases to find security risks before they become incidents. cnspec evaluates administrative accounts, default passwords, directly granted system privileges, roles, password and resource profiles, and initialization parameters.

cnspec connects over Oracle Net and inventories the database through read-only queries against the V$ views and the DBA_* data dictionary. It never touches your data. The provider uses a pure-Go driver, so it needs no Oracle Instant Client or other native libraries.

If you're new to cnspec, start with the Quickstart. For an overview of every database cnspec can scan, see the database scanning overview.

Prerequisites

To scan Oracle Database with cnspec, you must have:

Authenticate

cnspec authenticates with a database user and password, connecting to a service name or a SID:

cnspec shell oracledb db.contoso.com --service ORCLPDB1 --user auditor --ask-pass

Create a least-privileged auditing user. SELECT_CATALOG_ROLE reads everything the resources below need, without access to any application data:

CREATE USER auditor IDENTIFIED BY <password>;
GRANT CREATE SESSION, SELECT_CATALOG_ROLE TO auditor;

Without those catalog privileges the users, roles, profiles, and parameters collections come back empty rather than failing the scan. An ORA-00942 or ORA-01031 is treated as "not permitted," so confirm oracledb.instance.users is populated before trusting a passing account check.

For a multitenant database, connect to the pluggable database (PDB) service you want to audit. The DBA_* views then reflect that container.

Connection options

OptionDescription
--hostDatabase hostname or IP address (also accepted as the positional argument)
--portOracle Net listener port (default 1521)
--serviceService name to connect to, for example FREEPDB1 or ORCLPDB1
--sidSystem identifier, as an alternative to --service
--user, -uUser to authenticate as
--password, -pPassword, or --ask-pass to be prompted
--tlsConnect over TLS (TCPS)
--tls-insecureSkip TLS certificate verification (testing only)

Verify with a quick Oracle check

cnspec shell oracledb db.contoso.com --service ORCLPDB1 --user auditor --ask-pass
cnspec> oracledb.instance { version instanceName isCdb containerName }
oracledb.instance: {
  version: "23.26.2.0.0"
  instanceName: "FREE"
  isCdb: true
  containerName: "FREEPDB1"
}

If cnspec connects and shows the version, you're ready to scan.

Scan Oracle Database

cnspec scan oracledb db.contoso.com --service ORCLPDB1 --user auditor --ask-pass

When a scan completes, cnspec prints a summary of all the checks it ran, grouped by policy, along with a risk score from 0 (no risk) to 100 (highest risk). Failed checks include remediation guidance to help you fix issues. To learn more about reading scan results, read Understand cnspec Results.

Mondoo doesn't yet ship an out-of-the-box Oracle Database policy. The resources are shaped around the CIS Oracle Database Benchmark, so the checks below map closely to its recommendations. Use them as a starting point and create your own policies to meet your requirements.

Explore and test checks interactively

cnspec shell oracledb db.contoso.com --service ORCLPDB1 --user auditor --ask-pass

List users

cnspec> oracledb.instance.users { username accountStatus authenticationType oracleMaintained }

Read initialization parameters

cnspec> oracledb.instance.parameters.where(name == "audit_trail" || name == "sql92_security" || name == "resource_limit") { name value }
oracledb.instance.parameters.where: [
  0: { name: "audit_trail"    value: "NONE" }
  1: { name: "resource_limit" value: "TRUE" }
  2: { name: "sql92_security" value: "TRUE" }
]

Inspect a profile's password policy

cnspec> oracledb.instance.profiles.where(name == "DEFAULT") { name failedLoginAttempts passwordLifeTime passwordReuseMax passwordVerifyFunction }

List roles

cnspec> oracledb.instance.roles { name authenticationType oracleMaintained }

List a user's directly granted system privileges

cnspec> oracledb.instance.users.where(oracleMaintained == false) { username systemPrivileges roles }

Example security checks

Ensure no account still uses a default password

cnspec> oracledb.instance.users.where(accountStatus == "OPEN").none(hasDefaultPassword == true)
[ok] value: true

Ensure administrative connections are limited to SYS

An account with isAdmin can connect as SYSDBA or SYSOPER from the password file, bypassing normal authorization:

cnspec> oracledb.instance.users.where(isAdmin).all(username == "SYS")
[ok] value: true

Ensure no application account holds SELECT ANY DICTIONARY

That privilege reads the entire data dictionary, including every other account's metadata:

cnspec> oracledb.instance.users.where(oracleMaintained == false).none(systemPrivileges.contains("SELECT ANY DICTIONARY"))
[ok] value: true

Ensure no application account holds a blanket ANY privilege

cnspec> oracledb.instance.users.where(oracleMaintained == false) { username systemPrivileges.where(_ == /ANY/) }

Ensure auditing is enabled

cnspec> oracledb.instance.parameters.where(name == "audit_trail").none(value == "NONE")
[ok] value: true

Ensure resource limits are enforced

Without resource_limit, the profile limits below are recorded but never applied:

cnspec> oracledb.instance.parameters.where(name == "resource_limit").all(value == "TRUE")
[ok] value: true

Ensure remote OS authentication is off

remote_os_authent trusts the client operating system to say who the user is:

cnspec> oracledb.instance.parameters.where(name == "remote_os_authent").all(value == "FALSE")
[ok] value: true

Ensure every profile locks an account after failed logins

cnspec> oracledb.instance.profiles.none(failedLoginAttempts == "UNLIMITED")
[ok] value: true

Ensure every profile enforces password complexity

cnspec> oracledb.instance.profiles.none(passwordVerifyFunction == "NULL")
[ok] value: true

Ensure passwords expire

cnspec> oracledb.instance.profiles.none(passwordLifeTime == "UNLIMITED")
[ok] value: true

Ensure application accounts are not left on the DEFAULT profile

profile is a typed reference to the account's profile, so you can filter on it and traverse into its password policy rather than matching a bare name:

cnspec> oracledb.instance.users.where(oracleMaintained == false).none(profile.name == "DEFAULT")
[ok] value: true

Review accounts whose profile allows unlimited password reuse

cnspec> oracledb.instance.users.where(profile.passwordReuseMax == "UNLIMITED") { username profile { name } }

Learn more

On this page