Fundamental Security Part Two – Password Complexity and Defaults

June 2023 – Oracle 19C

So in the previous post we saw the creation of a PROFILE to add controls on user passwords, but we did not specify password complexity. By default, this is set to NULL in the profile, meaning no password complexity is enforced. This is a bad practice and must be changed.

PROFILE          RESOURCE_NAME             LIMIT
---------------- ------------------------- ---------
DEFAULT          PASSWORD_VERIFY_FUNCTION  NULL

Oracle provides a number of built-in password verification functions to set minimum length, complexity and the amount of character change required when entering a new password. Their details are as follows (Note that in 19C, VERIFY_FUNCTION_11G  and ORA12C_VERIFY_FUNCTION  are deprecated but still available)

Function NameLengthUpper Lower Numeric Special Differs-By
ORA12C_STIG_VERIFY_FUNCTION1511118
ORA12C_STRONG_VERIFY_FUNCTION922224
ORA12C_VERIFY_FUNCTION 811103
VERIFY_FUNCTION_11G 101103

Of the 4 build-in options, the ORA12C_STIG_VERIFY_FUNCTION is the “best” due to the level of complexity but mainly the length. Passwords need to be long to make them difficult to decrypt or crack. Having a guaranteed mix of upper case, lower case, numeric and special characters mean that there are a lot of possible options for each character position (over 70).

It is possible to write your own password complexity function, and Oracle provide the code for the above options in clear text in the file : $ORACLE_HOME/rdbms/admin/catpvf.sql


Simple example of creating your own custom password verification function based upon the built-in Oracle functions ora_complexity_check and ora_string_distance:


CREATE OR REPLACE FUNCTION custom_password_verify (
    username     VARCHAR2
  , password     VARCHAR2
  , old_password VARCHAR2
) RETURN BOOLEAN IS
    differ  INTEGER;
BEGIN
    IF NOT ora_complexity_check(
                               password
                             , chars => 15
                             , uppercase => 1
                             , lowercase => 1
                             , digit => 1
                             , special => 1
           ) THEN
        RETURN ( false );
    END IF;
    -- Check if the password differs from the previous password by n characters
    IF old_password IS NOT NULL THEN
        differ := ora_string_distance(old_password, password);
        IF differ < 8 THEN
            raise_application_error(-20000, 'password is too similar to previous password');
        END IF;

    END IF;
RETURN ( true );
END;
/

ALTER PROFILE default LIMIT PASSWORD_VERIFY_FUNCTION custom_password_verify;

NOTE: The function ORA_STRING_DISTANCE computes the Levenshtein distance between 2 words, which is the minimum number of single character edits required to change one word into the other.

It can be a good idea to match the complexity required within the Oracle database passwords with the complexity required with your corporate AD or LDAP password validation.

More on using AD or LDAP to authenticate within Oracle in another blog post.

WARNING

The PASSWORD_VERIFY_FUNCTION is a very powerful function which needs to be protected. Given that passwords are passed to it in clear text, and it is possible to subvert the procedure to perform illicit actions (such as keeping a backdoor permanently unlocked or recording everyones password) with the function, care should be taken to review and monitor the function for change and unexpected code.

Default Passwords

There are many standard Oracle accounts in existence, some of which are intrinsic to the running of the system such as SYS and SYSRAC. Some are automatically installed in the database, such as OUTLN or ORDDATA, and some are are simply well know, such as SCOTT or HR. These accounts have default passwords, which are commonly known to every hacker. Oracle provides as view which will display any accounts with a default password, called: DBA_USERS_WITH_DEFPWD

Installing a vanilla Oracle19.3 database and running a select yields the following results:


SQL > SELECT * FROM dba_users_with_defpwd;

USERNAME                       PRODUCT
------------------------------ ------------------------------
SYS
SYSTEM
CTXSYS

SQL > conn CTXSYS/CTXSYS
ERROR:
ORA-28000: The account is locked.

As we can see, the system believed SYS and SYSTEM have the default passwords, and CTXSYS definitely does have the default password! Fortunately, it is also locked by default, but it might be a good idea to change the password immediately.

However, SYS and SYSTEM force you to change the password on installation. There’s a minor bug which means the SHA1 hash which is used to identify default passwords is not updated at installation time. It is a good idea to re-change the SYS and SYSTEM password after install to update this and demonstrate to any audit or compliance officer running the above SELECT that the password is, indeed, not set to the default.

For more details about the underlying mechanisms which are used to allow this view to work, please check out Pete Finnegans blog post here

Now, lets look at old users…

Fundamental Security Part One – User Profiles

June 2023 – Oracle 19C

Stage 1 with our Fundamental Oracle Security… are you enforcing password rules with your database users and administrators? Do you have a standard to which you are adhering? Are the users forced to change their passwords regularly? Can they change it back again, maybe to something simple? What happens to the account when someone leaves the organisation?

One of the fundamental issues with Oracle is that it provides a lot of tools to enforce user compliance to standards, and a lot of it is turned off or has default settings which don’t comply with best practice. A good place to start is to use the Centre for Internet Security standards – CIS – to which many organisations are audited. It’s not perfect, but it’s a good place to approach to ensure a reasonable level of compliance and security.

Oracle provides USER PROFILES to help to manage user accounts. There is a DEFAULT profile, to which all users are allocated in the absence of other controls. However, the defaults are fairly loose and do not provide a great deal of protection when measured against the CIS standards.


DBA_PROFILES

Lets have a look at the defaults.

SELECT
    profile
  , resource_name
  , limit
FROM
    dba_profiles
WHERE
    resource_type = 'PASSWORD' and PROFILE = 'DEFAULT'
ORDER BY
    profile
  , resource_type
  , resource_name;


PROFILE  RESOURCE_NAME             LIMIT     CIS Recommendation
-------- ------------------------- --------- -----------------------------------
DEFAULT  FAILED_LOGIN_ATTEMPTS     10        FAIL <=   5
DEFAULT  INACTIVE_ACCOUNT_TIME     UNLIMITED FAIL <= 120 days(then lock)
DEFAULT  PASSWORD_GRACE_TIME       7         FAIL <=   5 days
DEFAULT  PASSWORD_LIFE_TIME        180       FAIL <=  90 days(enforced chg)
DEFAULT  PASSWORD_LOCK_TIME        1         PASS >=   1 day (duration locked)
DEFAULT  PASSWORD_REUSE_MAX        UNLIMITED FAIL >=  20     (pwd hist num)
DEFAULT  PASSWORD_REUSE_TIME       UNLIMITED FAIL >= 365 days(pwd hist days)
DEFAULT  PASSWORD_ROLLOVER_TIME    -1
DEFAULT  PASSWORD_VERIFY_FUNCTION  NULL      FAIL >= Password Complexity

As we can see, the DEFAULT profile assigned to users is far from meeting the CIS benchmark. What do these options mean?

Resource NameDescription
FAILED_LOGIN_ATTEMPTSHow many times can I get my password wrong before the account locks?
PASSWORD_LOCK_TIMEHow long should the password be locked following FAILED_LOGIN_ATTEMPTS ?
INACTIVE_ACCOUNT_TIMEHow long should I wait before locking an unused account automatically?
PASSWORD_GRACE_TIMEWhen a password expires, for how long should I give the user a warning message and still let them into the database?
PASSWORD_LIFE_TIME How long before the password needs to be changes?
PASSWORD_REUSE_MAXHow many historic passwords will I remember to prevent password reuse?
PASSWORD_REUSE_TIMEHow long will I remember passwords to prevent password reuse?
PASSWORD_ROLLOVER_TIMENew Feature from 19.12 – allow an account to remember and allow the previous password so I don’t need to change every client at exactly the same time. The account has 2 passwords for a while! This is extremely useful for application users where we may have hundreds of client application servers connecting to the database.
PASSWORD_VERIFY_FUNCTIONHow complex should the password be? The default is NULL meaning there is no password complexity enforced! It can be “X”.

How do I enforce better user control?

We need to create one or more profiles which comply with better standards than the defaults supplied. We will probably want more than one profile, as we will generally have more than one type of user – typical examples would be end users directly connecting, application accounts and database administrator accounts.

CREATE PROFILE cis_user_account LIMIT
       FAILED_LOGIN_ATTEMPTS     5
       INACTIVE_ACCOUNT_TIME     60
       PASSWORD_GRACE_TIME       5
       PASSWORD_LIFE_TIME        90
       PASSWORD_LOCK_TIME        1
       PASSWORD_REUSE_MAX        20
       PASSWORD_REUSE_TIME       365
       PASSWORD_ROLLOVER_TIME    0
       PASSWORD_VERIFY_FUNCTION  null];

ALTER USER neil_reporting   PROFILE cis_user_account ;
ALTER USER erik_reporting   PROFILE cis_user_account ;
ALTER USER martin_reporting PROFILE cis_user_account ;


CREATE PROFILE cis_app_account LIMIT
       FAILED_LOGIN_ATTEMPTS     5
       INACTIVE_ACCOUNT_TIME     120
       PASSWORD_GRACE_TIME       5
       PASSWORD_LIFE_TIME        365
       PASSWORD_LOCK_TIME        1
       PASSWORD_REUSE_MAX        20
       PASSWORD_REUSE_TIME       365
       PASSWORD_ROLLOVER_TIME    2
       PASSWORD_VERIFY_FUNCTION  null];

ALTER USER hr_app_user PROFILE cis_app_account ;

You many note that the cis_app_account profile has a longer PASSWORD_LIFE_TIME (365). This is not a good practice but it may be impractical to change the application account credentials on every application server every few months, like a user can. An exemption to the standard might be needed until it is possible to use automated tools such as Ansible and Liquibase to deploy new passwords to the application servers and database. The cis_app_account also has a PASSWORD_ROLLOVER_TIME of 2 days to allow a more controlled way to change the application password without stopping all of the application servers at the same time.

WARNING

Changing the PROFILE of a user may have unexpected consequences. A user who has not connected to the database for longer then the INACTIVE_ACCOUNT_TIME may suddenly lock and need to be unlocked. A user who has not changed their password for longer than PASSWORD_LIFE_TIME may suddenly lock and need to be unlocked. However, this does not happen immediately. There is a background processs which periodically check users against their PROFILE settings and takes action, so the account may lock several hour after you have changed the profile. If that is an application user, you may cause a system outage just when you do not expect it.

WARNING

Users who connect with system privileges, such as SYSDBA or SYSBACKUP have the ability to connect to the database even when the database is not available. As such, they do not update the LAST_LOGIN column in DBA_USERS. This means they are susceptible to being locked out by INACTIVE_ACCOUNT_TIME as the background process uses DBA_USERS.LAST_LOGIN to determine is the account should be locked. At the time of writing (in 19.15) , these accounts do not up the field in V$PWFILE_USERS.LAST_LOGIN either. The SYS account does not lock, so you can always access the database via SYS.

Password Complexity

But what about password complexity? We don’t want users to be able to use “X” as their password. We should all know that long passwords containing a combinations of elements – upper case, lower case, numeric and special characters – are the hardest to decrypt or brute-force. You have left the PASSWORD_VERIFY_FUNCTION as null! That is not compliant with any security standard, so what should we do here? This will take a bit more to explain…

Next, check out: Fundamental Security Part Two – Password Complexity and Defaults

Fundamental Oracle Security

June 2023 – Oracle 19C

Image from https://unsplash.com/@kellysikkema

Frequently I turn up at companies to resolve performance issues and migrate and upgrade systems. However, I have spent a fair bit of time recently working on security, from audit to helping with ransomware issues. The profile of security has increased significantly in recent years and I find that many companies are not even doing the basics. This is a short series of blogs showing the steps that everyone should be taking when commissioning new databases before a drop of code has been deployed. It can also be retrospectively added to existing databases, but that will take longer as there are many opportunities to cause an outage when implementing new security features.

DO NOT THINK BAD THINGS WILL NOT HAPPEN TO YOU!

Given enough time, they will. Make it harder for the hackers and data thieves, especially those within your organization.

The hard part of security is getting everyone to play by the rules. This is especially true of DBA’s, who can generally bypass any implemented security – and frequently do in the name of making their job easier to do. It’s true, minimising the level of security makes your job easier, but also makes the job of hackers easier too. Hackers aren’t all sat in dark rooms on foreign shores saying “Use SQL to corrupt their databases…”. Many data breaches are internal to your organization. Do you have sufficient monitoring and auditing to catch anyone extracting (large quantities of) your data, and the structures in place to prevent them from externalising it from your organization?

What standards are you looking to enforce? There are quite a few out there. You initially don’t want to be too extreme – switching from loose to very locked down in one step is quite dramatic and will alienate users and administrators alike. A good starting point is to take steps toward compliance with the Center for Internet Security (CIS) Benchmarks. You could then look at the STIG requirements (from the US Department of Defense Security Technical Implementation Guide) for further inspiration, or PCI-DSS standards used by – but not limited to – the payment card industry. For many organisations it will be difficult to comply with CIS standards, never mind anything more stringent – but getting close to compliance will make your systems harder to hack and will keep your data more secure. You also need to consider if you are overburdening the teams with excessive rules and processes to access your systems. The more layers and complexity you introduce, the more people will find workarounds to make their lives easier. Find the right balance.


Implementing Security

Oracle provide a lot of security features as part of the basic license, and a few cost options to enhance security and auditing too. This blog series will largely concentrate on what you get bundled with Enterprise Edition. However, you need to implement the features! No point having locks if you don’t use them!


There are many steps to take when securing a database. Click on each title to view the relevant blog post:

Fundamental Security Part One – User Profiles

Fundamental Security Part Two – Password Complexity and Defaults

Fundamental Security Part Three – Unused and Historic Accounts

Fundamental Security Part Four – Permissions Checking

Fundamental Security Part Five – Observability

Fundamental Security Part Six – Network Encryption

Fundamental Security Part Seven – Data Encryption At Rest

Fundamental Security Part Eight – Unified Audit