Security Advisory |
Profiles have been in the Oracle Database for decades and for decades, other than for a very small percentage of Oracle's customers they have been ignored which is a tremendous mistake.
At the bottom of this page are examples of how to make Profiles work for you. |
|
Recommended Security Rules |
NEVER
- Deploy a database where any user is assigned to Oracle's DEFAULT profile.
- Never deploy an Oracle database without modifying the DEFAULT profile so that it is unusable.
WITH GREAT CARE
- Design and implement profiles that make sense based on the application and the responsibilities of the users, human or mechanical, that connect to the application.
CAUTIONS
- The overwhelming majority of Oracle DBAs know the that PROFILE objects exist but have little more than a clue as to their value in improving security: Be sure that you are not one of them.
|
|
How Oracle Works |
Purpose |
Profiles are associated with individual users
Oracle defines two different categories of profile resource.
The first, Kernel Resources, makes it possible to specify resource availability for a group consisting of one or more users.
The second, Password Resources, makes it possible to specify password behavior for a group of one or more users.
Think of Password Resources as securing your database ... Kernel Resources as securing your data. |
All Oracle users are assigned a profile. If none is assigned Oracle assigns the DEFAULT profile that it created at the time of database creation. |
The first step in working with profiles is understanding their components, what they mean, and their impact on the security of your database. Let' start by viewing the options.
SELECT username, profile, created
FROM dba_users
ORDER BY 1;
USERNAME PROFILE CREATED
------------------------------ -------- --------------------
ANONYMOUS
DEFAULT 03-NOV-2020 09:37:59
APPQOSSYS
DEFAULT 03-NOV-2020 09:35:03
AUDSYS
DEFAULT 03-NOV-2020 09:24:41
CTXSYS
DEFAULT 03-NOV-2020 10:08:18
DBSFWUSER
DEFAULT 03-NOV-2020 09:26:43
DBSNMP
DEFAULT 03-NOV-2020 09:35:01
DGPDB_INT
DEFAULT 03-NOV-2020 09:33:16
DIP
DEFAULT 03-NOV-2020 09:26:25
DVF
DEFAULT 03-NOV-2020 10:22:12
DVSYS
DEFAULT 03-NOV-2020 10:22:12
GGSYS
DEFAULT 03-NOV-2020 09:35:17
GSMADMIN_INTERNAL
DEFAULT 03-NOV-2020 09:26:22
GSMCATUSER
DEFAULT 03-NOV-2020 09:35:08
GSMROOTUSER
DEFAULT 03-NOV-2020 09:26:22
GSMUSER
DEFAULT 03-NOV-2020 09:26:22
LBACSYS
DEFAULT 03-NOV-2020 10:21:45
MDDATA
DEFAULT 03-NOV-2020 10:12:05
MDSYS
DEFAULT 03-NOV-2020 10:12:04
OJVMSYS
DEFAULT 03-NOV-2020 10:04:36
OLAPSYS
DEFAULT 03-NOV-2020 10:11:25
ORACLE_OCM
DEFAULT 03-NOV-2020 09:27:47
ORDDATA
DEFAULT 03-NOV-2020 10:09:30
ORDPLUGINS
DEFAULT 03-NOV-2020 10:09:30
ORDSYS
DEFAULT 03-NOV-2020 10:09:30
OUTLN
DEFAULT 03-NOV-2020 09:24:43
REMOTE_SCHEDULER_AGENT
DEFAULT 03-NOV-2020 09:26:42
SI_INFORMTN_SCHEMA
DEFAULT 03-NOV-2020 10:09:30
SYS
DEFAULT 03-NOV-2020 09:24:40
SYS$UMF
DEFAULT 03-NOV-2020 09:32:26
SYSBACKUP
DEFAULT 03-NOV-2020 09:24:41
SYSDG
DEFAULT 03-NOV-2020 09:24:41
SYSKM
DEFAULT 03-NOV-2020 09:24:41
SYSRAC
DEFAULT 03-NOV-2020 09:24:41
SYSTEM
DEFAULT 03-NOV-2020 09:24:41
WMSYS
DEFAULT 03-NOV-2020 10:02:01
XDB
DEFAULT 03-NOV-2020 09:37:59
XS$NULL
DEFAULT 03-NOV-2020 09:26:40
37 rows selected.
Let's create two users ... the first without a PROFILE assignment, the second with an explicit assignment.
SQL> SELECT DISTINCT profile FROM dba_profiles ORDER BY 1;
PROFILE
------------------------------
C##GGADMIN
DEFAULT
ORA_STIG_PROFILE
CREATE USER profile_not_specified IDENTIFIED BY pns;
User created.
CREATE USER profile_specified IDENTIFIED BY psd
PROFILE ora_stig_profile;
CREATE USER profile_specified IDENTIFIED BY psd
*
ERROR at line 1:
ORA-28003: password verification for the specified password failed
ORA-20000: password length less than 15 bytes
Note that specifying the profile, which includes password verification prevents creation of a user with an inadequate password
CREATE USER profile_specified IDENTIFIED BY pR0filespe#ified
PROFILE ora_stig_profile;
User created.
The user is created because password now has an upper case letter, a number, and a special character.
Here's what we see in the data dictionary
SQL> SELECT username, profile
2 FROM dba_users
3 WHERE username LIKE '%PROF%SPEC%';
USERNAME PROFILE
---------------------------- ------------------------------
PROFILE_NOT_SPECIFIED DEFAULT
PROFILE_SPECIFIED ORA_STIG_PROFILE
The user created without specifying a PROFILE was assigned to DEFAULT. And that, by definition is a security risk because the DEFAULT profile, by default, offers essentially zero protection for the data or the database.
Here is what it specifies.
SQL> SELECT resource_name, resource_type, limit
2 FROM dba_profiles
3 WHERE profile = 'DEFAULT'
4 ORDER BY 2,1;
RESOURCE_NAME RESOURCE LIMIT
------------------------- -------- ----------
COMPOSITE_LIMIT KERNEL UNLIMITED
CONNECT_TIME KERNEL UNLIMITED
CPU_PER_CALL KERNEL UNLIMITED
CPU_PER_SESSION KERNEL UNLIMITED
IDLE_TIME KERNEL UNLIMITED
LOGICAL_READS_PER_CALL KERNEL UNLIMITED
LOGICAL_READS_PER_SESSION KERNEL UNLIMITED
PRIVATE_SGA KERNEL UNLIMITED
SESSIONS_PER_USER KERNEL UNLIMITED
FAILED_LOGIN_ATTEMPTS PASSWORD 10
INACTIVE_ACCOUNT_TIME PASSWORD UNLIMITED
PASSWORD_GRACE_TIME PASSWORD 7
PASSWORD_LIFE_TIME PASSWORD 180
PASSWORD_LOCK_TIME PASSWORD 1
PASSWORD_REUSE_MAX PASSWORD UNLIMITED
PASSWORD_REUSE_TIME PASSWORD UNLIMITED
PASSWORD_ROLLOVER_TIME PASSWORD 0
PASSWORD_VERIFY_FUNCTION PASSWORD NULL
17 rows selected.
Just seeing the word "UNLIMITED" should be
enough to convince you that this user has been created with far too much
permission. But it is worse than that ... the new user:
- Can connect forever
- Can use an unlimited amount of cpu starving other users
- Can be idle forever and not be disconnected
- Can perform a logical read of unlimited size (meaning they can steal
all of your data in a single statement)
- Can consume an unrestricted amount of the System Global Area (SGA)
- Can login again and again and create as many simultaneous sessions as they wish, all
similarly unrestricted
- Can mess up the password 10 times before the account is locked
- Can use an expired password for 7 days before the account is locked
- Only needs to change their password twice each year and can reuse the same password
- Has no validity checking on their password so a single letter is sufficient
There isn't a single part of this profile that makes even the slightest sense and the user just created has the ability to create a Distributed Denial Of Service (DDOS) attack because that is "the default".
You have a couple of choices if you are part of the 99%. You can do what most DBAs do and ignore the issue or you can fix it as shown below. |
Create one or more new profiles, one for Oracle system users, one for the members of the DBA team, and one or more additional profiles for everyone else.
If the database has both human user and mechanical users, for example connections from IOT devices do not share the same profile with both robots and humans. |
The first thing you must do to create usable, more secure, profiles is to classify the users into logical groups. For this demo we will create 2 groups. "DBAs" and "Everybody Else".
To keep this simple the demo will focus on a single resource: Our business rule will state that "A DBA can have up to 3 simultaneous sessions but a Report Writer is limited to only 1.
When you do this in your environment, unlike this demo, you should to specify every resource you don't want to have use a default, insecure, value.
SQL> CREATE PROFILE dba_profile LIMIT
2 sessions_per_user 3;
Profile created.
SQL> CREATE PROFILE everybody_else_profile LIMIT
2 sessions_per_user 1;
Profile created.
SQL> SELECT profile, resource_name, limit
2 FROM dba_profiles
3 WHERE profile IN ('DBA_PROFILE', 'EVERYBODY_ELSE_PROFILE')
4* AND limit <>'DEFAULT';
PROFILE RESOURCE_NAME LIMIT
----------------------- ------------------ -----
DBA_PROFILE SESSIONS_PER_USER 3
EVERYBODY_ELSE_PROFILE SESSIONS_PER_USER 1
Now we have a customized profile for members of the DBA team, one for "Everyone Else", and we recommend creating a profile for SYS, SYSTEM,
and other Oracle default accounts that is identical to what Oracle provides but naming it something harmless like 'READONLY' so it doesn't attract attention.
All you have to do to get everyone off the DEFAULT profile now is move them.
SQL> SELECT profile FROM dba_users WHERE username = 'SCOTT';
PROFILE
-----------------------
DEFAULT
SQL> alter user scott PROFILE EVERYBODY_ELSE_PROFILE;
User altered.
SQL> SELECT profile FROM dba_users WHERE username = 'SCOTT';
PROFILE
------------------------------
EVERYBODY_ELSE_PROFILE
This step is a success when no users is currently assigned to the DEFAULT profile.
SQL> SELECT UNIQUE username
2 FROM dba_users
3 WHERE profile = 'DEFAULT';
no rows selected |
Maximum Security Default Profile
Now that legitimate users connecting to the database no longer require the DEFAULT profile the only way anyone should be assigned it is a DBA not following security procedures or someone trying to hack the system.
By limiting everything the default profile authorizes DBA errors will be
quickly found and hackers will have to work far harder to create a gain
access. |
The following list isn't intended to be complete but
rather to illustrate the high approach.
SQL> ALTER PROFILE DEFAULT LIMIT
2 CONNECT_TIME 1
3 CPU_PER_CALL 1
4 CPU_PER_SESSION 1
5 FAILED_LOGIN_ATTEMPTS 1
6 IDLE_TIME 1
7 INACTIVE_ACCOUNT_TIME 15
8 LOGICAL_READS_PER_CALL 1
9 LOGICAL_READS_PER_SESSION 1
10 PASSWORD_GRACE_TIME 0
11 PASSWORD_LIFE_TIME 0.00001
12 PASSWORD_LOCK_TIME UNLIMITED
13 PASSWORD_REUSE_MAX 1
14 PASSWORD_REUSE_TIME 9999
15 PASSWORD_ROLLOVER_TIME 0
16 PASSWORD_VERIFY_FUNCTION ORA12C_STIG_VERIFY_FUNCTION
17 PRIVATE_SGA 1
18* SESSIONS_PER_USER 1;
Profile created.
I don't think anyone is doing too much damage with this profile that we will assign to the user "test".
SQL> conn test/"testTES#T!2test";
ERROR:
ORA-02394: exceeded session limit on IO usage, you are being logged off
And, as you can see, an I/O limit set to 1 forces a failure. No one, not assigned to a valid profile has much chance of hacking this database.
What was done in this demo is within the existing license agreement of every Oracle customer and would require no more than an hour's effort. So what are you waiting for?
Get approval, define the logical user groups, write the script, run first in Dev, then Test, and get final approval before migrating to production. |
|
Profile Information |
Dependencies |
CDB_PROFILES |
KU$_USER_BASE_VIEW |
PROFNAME$ |
DBA_PROFILES |
PROFILE$ |
RESOURCE_MAP |
KU$_PWDVFC_VIEW |
|
|
|
Documented |
Yes |
Exceptions |
Error Code |
Reason |
ORA-02017 |
Integer Value Required |
ORA-02377 |
Invalid Profile Limit |
|
Security Model |
Owned by SYS |
Source |
The default profile is created by {$ORACLE_HOME}/rdbms/admin/denv.bsq
Modifications that improve governance, compliance, and security can be found, commented out, in {$ORACLE_HOME}/rdbms/admin/utlpwdmg.sql
Password verify function DDL is in $ORACLE_HOME/rdbms/admin/catpvf.sql. |
System Privileges |
ALTER PROFILE |
CREATE PROFILE |
DROP PROFILE |
|
|
Profile Discovery and Resources |
Profile Discovery |
The first step in working with Profiles is to determine the names of profiles that exist in the database.
col profile_name format a20
col flag format a30
SELECT profile#, name AS PROFILE_NAME,
DECODE(flags, 1, 'Common (CDB or App)',
2, 'App
Common',
4, 'Implicit App',
8, 'Oracle Supplied',
16, 'Mandatory',
flags) AS FLAG
FROM profname$
ORDER BY name;
PROFILE# PROFILE_NAME FLAGS
---------- -------------------- ----------------
0 DEFAULT Oracle Built-in
1 ORA_CIS_PROFILE Oracle Built-in
2 ORA_STIG_PROFILE Oracle Built-in
In a container database you can create regular profiles in a PDB but you must create a COMMON PROFILE in CDB$ROOT.
The following might be a reasonable starting point for a profile for a GoldenGate admin schema.
conn / as sysdba
show con_name
CON_NAME
------------------------------
CDB$ROOT
CREATE PROFILE ggadmin LIMIT
PASSWORD_GRACE_TIME 10
PASSWORD_REUSE_TIME 9999
PASSWORD_REUSE_MAX 1
FAILED_LOGIN_ATTEMPTS 3
PASSWORD_LOCK_TIME 1
PASSWORD_VERIFY_FUNCTION ora12c_strong_verify_function;
CREATE PROFILE ggadmin LIMIT
*
ERROR at line 1:
ORA-65140: invalid common profile name
If we move the session from CDB$ROOT to a PDB the profile is created with the legacy name.
ALTER SESSION SET container=PDBDEV;
Session altered.
CON_NAME
------------------------------
PDBDEV
CREATE PROFILE ggadmin LIMIT
PASSWORD_GRACE_TIME 10
PASSWORD_REUSE_TIME 9999
PASSWORD_REUSE_MAX 1
FAILED_LOGIN_ATTEMPTS 3
PASSWORD_LOCK_TIME 1
PASSWORD_VERIFY_FUNCTION ora12c_verify_function;
Profile created.
In the root container you must use the container prefix which defaults to C## at installation.
ALTER SESSION SET container=CDB$ROOT;
Session altered.
CREATE PROFILE c##ggadmin LIMIT
PASSWORD_GRACE_TIME 10
PASSWORD_REUSE_TIME 9999
PASSWORD_REUSE_MAX 1
FAILED_LOGIN_ATTEMPTS 3
PASSWORD_LOCK_TIME 1
PASSWORD_VERIFY_FUNCTION ora12_stig_verify_function;
Profile created.
SELECT profile#, name AS PROFILE_NAME,
DECODE(flags, 0, 'Oracle Built-in',
1, 'Common',
2, 'App Common',
4, 'Implicit',
flags) AS FLAG
FROM profname$
ORDER BY name;
PROFILE# PROFILE_NAME FLAG
---------- -------------------- --------------------
3 C##GGADMIN Common
0 DEFAULT
8
1 ORA_CIS_PROFILE
8
2 ORA_STIG_PROFILE
8
Looking at the above listing you may be wondering what happened to the GGADMIN profile created just a few minutes earlier in PDBDEV. Check the PROFNAME$ table in that PDB.
Data Dictionary tables do not have a con_id column identifying the container as do the CDB_ view.
SELECT DISTINCT con_id, profile
FROM cdb_profiles
ORDER BY 1,2;
CON_ID PROFILE
------- -----------------
1 C##GGADMIN
1 DEFAULT
1 ORA_STIG_PROFILE
3 C##GGADMIN
3 DEFAULT
3 GGADMIN
3 ORABASE_DBA
3 ORA_STIG_PROFILE |
Type 0, Kernel Resources |
col name format a30
SELECT name, resource#
FROM resource_map
WHERE type# = 0
ORDER BY 1;
NAME RESOURCE#
--------------------------- ---------
COMPOSITE_LIMIT 0
CONNECT_TIME 7
CPU_PER_CALL 3
CPU_PER_SESSION 2
IDLE_TIME 6
LOGICAL_READS_PER_CALL 5
LOGICAL_READS_PER_SESSION 4
PRIVATE_SGA 8
SESSIONS_PER_USER 1 |
COMPOSITE_LIMIT |
Maximum weighted sum of: CPU_PER_SESSION, CONNECT_TIME, LOGICAL_READS_PER_SESSION, and PRIVATE_SGA. If this limit is exceeded, Oracle aborts the session and returns an error.
composite_limit <value | UNLIMITED | DEFAULT> |
ALTER PROFILE developer LIMIT composite_limit 5000000; |
CONNECT_TIME |
Allowable connect time per session in minutes
connect_time <value | UNLIMITED | DEFAULT> |
ALTER PROFILE developer LIMIT connect_time 600; |
CPU_PER_CALL |
Maximum CPU time per call (100ths of a second)
cpu_per_call <value | UNLIMITED | DEFAULT> |
ALTER PROFILE developer LIMIT cpu_per_call 3000; |
CPU_PER_SESSION |
Maximum CPU time per session (100ths of a second)
cpu_per_session <value | UNLIMITED | DEFAULT> |
ALTER PROFILE developer LIMIT cpu_per_session UNLIMITED; |
IDLE_TIME |
Allowed idle time before user is disconnected (minutes)
idle_time <value | UNLIMITED | DEFAULT> |
ALTER PROFILE developer LIMIT idle_time 20; |
LOGICAL_READS_PER_CALL |
Maximum number of database blocks read per call
logical_reads_per_call <value | UNLIMITED | DEFAULT> |
ALTER PROFILE developer LIMIT logical_reads_per_call 1000; |
LOGICAL_READS_PER_SESSION |
Maximum number of database blocks read per session
logical_reads_per_session <value | UNLIMITED | DEFAULT> |
ALTER PROFILE developer LIMIT logical_reads_per_session UNLIMITED; |
Type 1 Password Resources |
SQL> col name format a30
SQL> SELECT name, resource#
2 FROM resource_map
3 WHERE type# = 0
4* ORDER BY 1;
NAME RESOURCE#
--------------------------- ---------
FAILED_LOGIN_ATTEMPTS 0
INACTIVE_ACCOUNT_TIME 7
PASSWORD_GRACE_TIME 6
PASSWORD_LIFE_TIME 1
PASSWORD_LOCK_TIME 5
PASSWORD_REUSE_MAX 3
PASSWORD_REUSE_TIME 2
PASSWORD_VERIFY_FUNCTION 4 |
FAILED_LOGIN_ATTEMPTS
The number of failed attempts to log in to the user account before the account is locked
(new 12.2) |
failed_login_attempts <value | UNLIMITED | DEFAULT> |
ALTER PROFILE developer LIMIT failed_login_attempts 3;
-- to count failed log in attempts:
SELECT name, lcount
FROM user$
WHERE lcount <> 0; |
INACTIVE_ACCOUNT_TIME
The number of days of non-use before an account is automatically locked |
Starting with this release, you can use the INACTIVE_ACCOUNT_TIME parameter to automatically lock the account of a database user who has not logged in to the database instance in a specified number of days
idle_time <value | UNLIMITED | DEFAULT> |
ALTER PROFILE developer LIMIT inactive_account_time 35; |
PASSWORD_GRACE_TIME
The number of days during which a login is allowed but a warning is issued |
password_gracetime <value | UNLIMITED | DEFAULT> |
ALTER PROFILE developer LIMIT password_grace_time 10; |
PASSWORD_LIFE_TIME
The number of days the same password can be used for authentication |
password_life_time <value | UNLIMITED | DEFAULT> |
ALTER PROFILE developer LIMIT password_life_time 60; |
PASSWORD_LOCK_TIME
The number of days an account will be locked after the specified number of consecutive failed login attempts defined |
password_lock_time <value | UNLIMITED | DEFAULT> |
ALTER PROFILE developer LIMIT password_lock_time 30; |
PASSWORD_REUSE_MAX
Times a password can be reused |
password_reuse_max <value | UNLIMITED | DEFAULT> |
ALTER PROFILE developer LIMIT password_reuse_max 99; |
PASSWORD_REUSE_TIME
Days between password reuses |
password_reuse_time <value | UNLIMITED | DEFAULT> |
ALTER PROFILE developer LIMIT password_reuse_time 9999; |
PASSWORD_ROLLOVER_TIME
Days during which both old and new passwords are valid (new 21c) |
password_rollover_time <value | DEFAULT> |
ALTER PROFILE default LIMIT password_rollover_time
0; |
PASSWORD_VERIFY_FUNCTION
Enforces password complexity |
password_reuse_time <value | UNLIMITED | DEFAULT> |
ALTER PROFILE developer develop ZZYZXpassword_verify_function 9999; |
|
Password Verification |
Sample script for creating a password verify function |
{ORACLE_HOME}/rdbms/admin/utlpwdmg.sql
Note that the 12c password verify function has a different name and enhanced functionality |
PASSWORD_VERIFY_FUNCTION
Verifies a passwords for length, content, and complexity |
password_verify_function <function_name | NULL | DEFAULT> |
ALTER PROFILE developer LIMIT
password_verify_function uw_pwd_verification; |
Changing passwords with a password verify function |
The function requires the old and new passwords so password changes can not be done with ALTER USER. Password changes should be performed with the SQL*Plus PASSWORD command or through a stored procedure that requires the correct inputs. |
|
Password Verify Functions |
Note |
Oracle 12.2-19 come with 3 different password verify functions with DDL in $ORACLE_HOME/rdbms/admin/catpvf.sql.
While other versions exist in 12c the only function worth using is the name named ora12c_stig_verify_function. |
ora_complexity_check |
If not null, each of the following parameters specifies the minimum number of characters of the corresponding type.
- chars - All characters (i.e. string length)
- letter - Alphabetic characters A-Z and a-z
- upper - Uppercase letters A-Z
- lower - Lowercase letters a-z
- digit - Numeric characters 0-9
- special - All characters not in A-Z, a-z, 0-9 except double quote which is a password delimiter
|
ora_string_distance |
Calculates the Levenshtein distance between two strings 's' and 't'.
The Levenshtein distance between two words is the minimum number of single-character edits (insertion, deletion, substitution) required to change one word into the other. |
ora12c_stig_verify_function |
This function is provided to give stronger password complexity function that would take into consideration recommendations from Department of Defense Database Security Technical Implementation Guide (STIG) v1 r2 released on 22-Jan-2016. |
ora12c_strong_verify_function |
Provided from 12c onwards for stringent password check requirements |
ora12c_verify_function |
Makes the minimum complexity checks like the minimum length of the password, password not same as the username, etc.
The user may enhance this function according to the need. This function must be created in SYS schema. connect sys/<password> as sysdba before running the script |
verify_function |
Sets the default password resource parameters. This script needs to be run to enable the password features. However the default resource parameters can be changed based on the need. A default password complexity function is also provided.
This function makes the minimum complexity checks like the minimum length of the password, password not same as the username, etc. The user may enhance this function according to the need.
This function must be created in SYS schema.
connect sys/<password> as sysdba before running the script |
verify_function_11g |
Makes the minimum complexity checks such as the minimum length of the password, password not same as the username, etc. Oracle says the user may enhance this function according to their need.
But it is of minimum value and should be ignored. Customize the strongest, not the weakest, to get maximum value for your effort. |
|
Profile Security Enahncements |
If what you are looking for is security significantly better than what Oracle provides then there are two places in the profile you should consider as you limit what users can do.
The first is a guidance, not finished code, to improve the Password Verification function by adding a dictionary of real words.
The second is based on the fact that end-users that logged in through a website should never be able to grab such a large percentage of available resources that they can either access more data than they could reasonably require or could create a DDOS attack.
Consider the following scenario with respect to using the Profile to limit resources. Assume you have a table with 143,000,000 records related to credit cards. Assume further a member of the public is logging into your database to look at their own information.
Do they need to be able to return a result set of 143,000,000 rows? Do they need to return a query result of even 100 rows?
Talk to subject matter experts in your organization and find out the maximum amount of data an individual accessing your application could legitimately ask for. Then test what that means in terms of SGA and Logical I/O. Then limit that PROFILE accordingly. |
Search for common words embedded in passwords |
-- Step 1: download words.txt from https://github.com/dwyl/english-words
We stored it in a directory pointed to by the database directory object ctemp.
CREATE OR REPLACE DIRECTORY ctemp AS 'c:\temp';
CREATE TABLE words_xtab (
wordtext VARCHAR2(50))
ORGANIZATION EXTERNAL (
TYPE oracle_loader
DEFAULT DIRECTORY ctemp
ACCESS PARAMETERS (
RECORDS DELIMITED BY 0x'0a' CHARACTERSET WE8ISO8859P1
FIELDS TERMINATED BY '|'
MISSING FIELD VALUES ARE NULL
REJECT ROWS WITH ALL NULL FIELDS
(wordtext))
LOCATION('words.txt'))
-- Step 2: Load the external table into an Oracle table using an external table
-- and make the internal table case insensitive
CREATE TABLE verify_words AS
SELECT lower(wordtext) FROM words_xtab;
DELETE FROM verify_words
WHERE length(wordtext) < 3;
DELETE FROM verify_words
WHERE INSTR(wordtext, '.', 1, 1) <> 0;
COMMIT;
-- Step 3: Drop the external table and delete the file
DROP TABLE words_xtab;
CREATE OR REPLACE FUNCTION ora12c_dbswx_verify_function(username IN VARCHAR2, password IN VARCHAR2, old_password IN VARCHAR2)
RETURN BOOLEAN AUTHID DEFINER IS
differ INTEGER;
BEGIN
IF NOT ora_complexity_check(password, chars => 15, upper => 1, lower => 1, digit => 1, special => 1) THEN
RETURN(FALSE);
END IF;
IF old_password IS NOT NULL THEN
differ := ora_string_distance(old_password, password);
IF differ < 8 THEN
RAISE_APPLICATION_ERROR(-20033, 'New password must significantly differ from the previous password');
END IF;
END IF;
BEGIN
-- assign to a variable the new password stripped of numbers and special characters
-- convert the "stripped" new password to lower case
-- test the "stripped" new password against the words in the verify_words table
-- test again using the reverse function against the words in the verify_words table
-- assign the new password to a variable after converting numbers to similar letters
-- also convert special characters to most likely substitutions, ie "!" to 1
-- also removing any special character at the far right end of the string
-- test as above
-- return FALSE or RAISE an exception if a match is found
END;
RETURN TRUE;
END ora12c_dbsxw_verify_function;
/
GRANT EXECUTE ON ora12c_dbsxw_verify_function TO PUBLIC container=current;
-- as much as we dislike grants to PUBLIC this is an exception |
Limiting resources so that a query cannot return more data than is legitimately required |
conn sys@pdbdev as sysdba
SQL> SELECT profile
2 FROM dba_users
3* WHERE username = 'UWCLASS';
PROFILE
--------
DEFAULT
col resource_name format a26
col limit format a11
SQL> SELECT resource_name, limit
2 FROM dba_profiles
3 WHERE profile = 'DEFAULT'
4 AND resource_name LIKE 'LOGICAL%'
5 ORDER BY 1;
RESOURCE_NAME LIMIT
-------------------------- -----------
LOGICAL_READS_PER_CALL UNLIMITED
LOGICAL_READS_PER_SESSION UNLIMITED
SQL> ALTER PROFILE DEFAULT LIMIT
2 LOGICAL_READS_PER_CALL 100;
Profile altered.
conn uwclass/uwclass@pdbdev
SQL> SELECT COUNT(*) FROM airplanes;
SELECT COUNT(*) FROM airplanes
*
ERROR at line 1:
ORA-02395: exceeded call limit on IO usage
SQL> SELECT COUNT(*) FROM airplanes
2* WHERE rownum < 37500;
COUNT(*)
----------
37499
-- Note: An exception is not raised when a smaller number of rows is accessed.
-- 100 reads per call limits rows retrieved fewer than 37749 for this statement.
-- assuming a hacker was trying to steal 145,000,000 rows to do so with this
-- limit would take 3,840+ statements uniquely crafted statements.
-- If we reduce logical reads further the number of statements required to steal
-- the data increases as does the ability to catch the thief.
-- Add to this other profile capabilities, Row Level ecurity, and new 12c row
-- limiting capabilities and an Experian-type breach can be rendered impossible
-- from the practical standpoint. |
|
Create Profiles |
View existing profile |
col profile format a20
col limit format a20
SQL> SELECT profile, resource_name, limit
2 FROM dba_profiles
3* ORDER BY profile, resource_name;
PROFILE RESOURCE_NAME LIMIT
-------------------- -------------------------------- --------------------
DEFAULT COMPOSITE_LIMIT UNLIMITED
DEFAULT CONNECT_TIME UNLIMITED
DEFAULT CPU_PER_CALL UNLIMITED
DEFAULT CPU_PER_SESSION UNLIMITED
DEFAULT FAILED_LOGIN_ATTEMPTS 10
DEFAULT IDLE_TIME UNLIMITED
DEFAULT INACTIVE_ACCOUNT_TIME UNLIMITED
DEFAULT LOGICAL_READS_PER_CALL UNLIMITED
DEFAULT LOGICAL_READS_PER_SESSION UNLIMITED
DEFAULT PASSWORD_GRACE_TIME 7
DEFAULT PASSWORD_LIFE_TIME 180
DEFAULT PASSWORD_LOCK_TIME 1
DEFAULT PASSWORD_REUSE_MAX UNLIMITED
DEFAULT PASSWORD_REUSE_TIME UNLIMITED
DEFAULT PASSWORD_VERIFY_FUNCTION NULL
DEFAULT PRIVATE_SGA UNLIMITED
DEFAULT SESSIONS_PER_USER UNLIMITED |
Create Center for Internet Security (CIS) profile |
CREATE PROFILE <profile_name> LIMIT
<profile_item_name> <value>
<profile_item_name> <value>
...
[CONTAINER = <CURRENT | ALL>; |
-- log into cdb$root
SQL conn / as sysdba
SQL> CREATE PROFILE ggadmin LIMIT
2 PASSWORD_GRACE_TIME 10
3 PASSWORD_REUSE_TIME 9999
4 PASSWORD_REUSE_MAX 1
5 FAILED_LOGIN_ATTEMPTS 3
6 PASSWORD_LOCK_TIME 1
7 PASSWORD_VERIFY_FUNCTION ora12c_verify_function;
CREATE PROFILE ggadmin LIMIT
*
ERROR at line 1:
ORA-65140: invalid common profile name
SQL> ed
Wrote file afiedt.buf
1 CREATE PROFILE
c##ggadmin LIMIT
2 PASSWORD_GRACE_TIME 10
3 PASSWORD_REUSE_TIME 9999
4 PASSWORD_REUSE_MAX 1
5 FAILED_LOGIN_ATTEMPTS 3
6* PASSWORD_LOCK_TIME 1
7 PASSWORD_VERIFY_FUNCTION ora12c_verify_function
SQL> /
Profile created.
-- log into a pdb
SQL> conn sys@pdbdev as sysdba
Enter password:
Connected.
SQL> CREATE PROFILE ggadmin LIMIT
2 PASSWORD_GRACE_TIME 10
3 PASSWORD_REUSE_TIME 9999
4 PASSWORD_REUSE_MAX 1
5 FAILED_LOGIN_ATTEMPTS 3
6 PASSWORD_LOCK_TIME 1
7 PASSWORD_VERIFY_FUNCTION ora12c_verify_function;
Profile created. |
|
Alter Profile |
Alter profile syntax |
ALTER PROFILE <profile_name> LIMIT <profile_item_name> <value>; |
ALTER PROFILE developer LIMIT FAILED_LOGIN_ATTEMPTS 3; |
Modify Oracle 12.2 default profile for Center for Internet Security (CIS) |
ALTER PROFILE DEFAULT LIMIT
PASSWORD_LIFE_TIME 90
PASSWORD_GRACE_TIME 3
PASSWORD_REUSE_TIME 365
PASSWORD_REUSE_MAX 20
FAILED_LOGIN_ATTEMPTS 3
PASSWORD_LOCK_TIME 1
PASSWORD_VERIFY_FUNCTION ora12c_verify_function; |
Modify Oracle 12.2 default profile for DOD Security Technical Implementation Guidelines (STIG)
The STIG profile is created as a local object with container = current. Exception is made in PDB code similar to the DEFAULT profile to make sure the STIG profile is created in every container during DB creation time. |
ALTER PROFILE DEFAULT LIMIT
PASSWORD_LIFE_TIME 60
PASSWORD_REUSE_TIME 365
PASSWORD_REUSE_MAX 5
FAILED_LOGIN_ATTEMPTS 3
PASSWORD_VERIFY_FUNCTION ora12c_strong_verify_function; |
|
Assign Profile |
Assign During User Creation |
CREATE USER <user_name>
IDENTIFIED BY <password>
PROFILE <profile_name>; |
CREATE USER uwclass
IDENTIFIED BY "N0Way!"
DEFAULT TABLESPACE uwdata
TEMPORARY TABLESPACE temp
QUOTA 0 ON SYSTEM
QUOTA 0 ON SYSAUX
QUOTA UNLIMITED ON uwdata
QUOTA 10M ON indx_sml
PROFILE developer; |
Assign Profile After User Creation |
ALTER USER <user_name>
PROFILE <profile_name>; |
ALTER USER uwclass PROFILE developer; |
|
Drop Profile |
Drop Profile without Users |
DROP PROFILE <profile_name>; |
DROP PROFILE developer; |
Drop Profile with associated Users |
DROP PROFILE <profile_name> CASCADE; |
DROP PROFILE developer CASCADE; |