Showing posts with label Oracle Security. Show all posts
Showing posts with label Oracle Security. Show all posts

Thursday, March 29, 2012

what comes next, after enabling audit?

After enabling and setting the audit options, another process should start, surveillance. As everyone can figure it out easily, auditing is not for just setting and leave it alone. Responsible group should inspect the reports in a timely fashion. DBA can obtain these kind of reports with a time window. Or a centralized logging application can be installed. Oracle also has an "Audit Vault" product for this purpose which collects the audit data from all databases and produces reports to the audit and/or data security departments.

In this individual case, i have created Custom Reports for the most common cases in Oracle Enterprise Manager Grid Control. The mentioned reports are sent to the Security and Audit departments in a daily basis. The output of the SQL commands below are also collected by a centralized logging application.

Some assumptions should be made in order to understand the following queries. First of all the application users (database users which are ment to be used by only through the application interface) are grouped into the application profiles. By assigning individual profiles to the application. dblink. admin users etc.. , DBA can force the password complexity and password lifetime values dedicated to the application behaviour. Clearly, nobody wants to have a critical downtime of a frequently used application because of a password lock of the application user in the middle of the daytime (so, yes I prefer password_lifetime value of the application related users to unlimited). But this subject belongs to some other topic about security.

Probably one of the most important audit data to be reported is the connections to the database with the application users. Because of the high amount of the data produced by the application user actions, in most of the cases auditing every operation of the application user is impossible. But this reveals a vulnerability which is; any user connects to the database with the application user can do anything without a trace. So it is very important to audit the connections with the application user and from a source outside of the application server(s) which means from a workstation.


-- all access from application users via workstations
select   
  OS_USERNAME, 
  USERNAME, 
  USERHOST, 
  TERMINAL, 
  TIMESTAMP,    
  OWNER,         
  OBJ_NAME,
  ACTION_NAME,         
  COMMENT_TEXT,      
  SQL_TEXT,
  RETURNCODE    
  from sys.dba_audit_trail
  where username in 
    (select username 
      from dba_users 
      where profile in 
        (select 
           distinct(profile) 
         from 
           dba_profiles 
         where profile like '%APPLICATION%')) 
  and lower(userhost) not in (select hostname from t_application_servers)
  and os_username != 'debug'
  and action_name in ('LOGON','LOGOFF')
  and timestamp > sysdate-7
  order by timestamp desc;



Any drop table operation should be reported if the action user is not an application user. Operation itself may not be risky at all times because any user can drop any object from their own schemas. But still this operation should be reported in timely fashion to be sure that nobody is dropping a vital object/table for the sake of the application avalibility.


-- unknown user drops or truncates any table
select 
  OS_USERNAME, 
  USERNAME, 
  USERHOST, 
  TERMINAL, 
  TIMESTAMP,    
  OWNER,         
  OBJ_NAME,
  ACTION_NAME,         
  COMMENT_TEXT,      
  SQL_TEXT,
  RETURNCODE    
  from sys.dba_audit_trail  
  where username not in 
      (select username 
      from dba_users 
      where profile in 
        (select 
           distinct(profile) 
         from 
           dba_profiles 
         where profile like '%APPLICATION%')) 
  and action_name in ('TRUNCATE TABLE','DROP TABLE','DROP INDEX')
  and timestamp > sysdate-7
  order by timestamp desc;



Object privileges are very important, when a DBA breaks his/her rules and the rest comes in a very short time. Any privilege granted to any user out of the roles should be reported and investigated. If this is a temporary grant then it should be followed up to be revoked.


-- any grant to unauthorized user
select 
  OS_USERNAME, 
  USERNAME, 
  USERHOST, 
  TERMINAL, 
  TIMESTAMP,    
  OWNER,         
  OBJ_NAME,
  GRANTEE,
  ACTION_NAME,         
  COMMENT_TEXT,      
  SQL_TEXT,
  RETURNCODE  
  from sys.dba_audit_trail
  where grantee not in 
    (select username 
      from dba_users 
      where profile in 
        (select 
           distinct(profile) 
         from 
           dba_profiles 
         where profile like '%APPLICATION%')) 
  and action_name like 'GRANT%'
  and timestamp > sysdate-7
  order by timestamp desc;



Public synonyms and public dblinks makes the general database operation very easy going. But these objects also cause severe security impact on the operation of the database. Application operation can easly be directed to custom created tables or dblinks and cause unwanted actions and operations. These public object creations should be investigated and followed in a timely fashion.


-- create public synonym or create public dblink where user is not dba
select 
  OS_USERNAME, 
  USERNAME, 
  USERHOST, 
  TERMINAL, 
  TIMESTAMP,    
  OWNER,         
  OBJ_NAME,
  ACTION_NAME,         
  COMMENT_TEXT,      
  SQL_TEXT,
  RETURNCODE  
  from sys.dba_audit_trail
  where username not in 
    (select username 
      from dba_users 
      where profile in 
        ('DBA_PROFILE'))
  and (action_name='CREATE PUBLIC SYNONYM' or action_name='CREATE PUBLIC DBLINK')
  and timestamp > sysdate-7
  order by timestamp desc;



Alter System or Alter Database operations should only be done by the privileged DBA's (please note that in this database all DBA users are grouped in a profile named DBA_PROFILE). Any user tries or even successes the Alter System or Alter Database command should be reported immediately. The list of the users for the last one week can be obtained from the following query.


-- alter system and alter database operations where user not in dba list 
select
  OS_USERNAME, 
  USERNAME, 
  USERHOST, 
  TERMINAL, 
  TIMESTAMP,    
  OWNER,         
  OBJ_NAME,
  ACTION_NAME,         
  COMMENT_TEXT,      
  SQL_TEXT,
  RETURNCODE   
  from sys.dba_audit_trail
  where  username not in 
    (select username 
      from dba_users 
      where profile in 
        ('DBA_PROFILE'))
  and (action_name like 'ALTER SYSTEM' or action_name like 'ALTER DATABASE')
  and timestamp > sysdate-7
  order by timestamp desc;



Any operation from any user (out of the application users) should be reported if they are trying (or successes) to change/alter an object in another schema. This can be normal development operation but in some cases it can be considered as an unwantend operation.


-- any operation within another schema
select
  OS_USERNAME, 
  USERNAME, 
  USERHOST, 
  TERMINAL, 
  TIMESTAMP,    
  OWNER,         
  OBJ_NAME,
  GRANTEE,
  ACTION_NAME,         
  COMMENT_TEXT,      
  SQL_TEXT,
  RETURNCODE  
  from sys.dba_audit_trail  
  where username not in      
      (select username 
      from dba_users 
      where profile in 
        (select 
           distinct(profile) 
         from 
           dba_profiles 
         where profile like '%APPLICATION%'))    
  and username != owner 
  and action_name not in ('LOGOFF', 'LOGON', 'LOGOFF BY CLEANUP') 
  and timestamp > sysdate-7
  order by timestamp desc;



Last but not the least failed login attemps may also be reported. Actually there will be some output of this query but in case of the count of the records are rising up inexplicably then the reason of this rise should be investigated as it may be someone is trying to login continously (If "failed login attemps" value is not set in the database profile).


-- failed login attempt
select 
  os_username, 
  username, 
  userhost, 
  timestamp, 
  returncode 
from 
  dba_audit_session
where 
  action_name = 'LOGON'
  and returncode > 0 
  and timestamp > sysdate-7
  order by timestamp;




Here I can provide only my experiences of the further reporting of the Oracla Database Audit option. Of course this list of reports can be widen or broaden according to the audit/security department needs or expects from the database administrators which should be decided all together.

Tuesday, February 21, 2012

which audit options should be enabled

Enabling audit option for an Oracle Database is a smooth operation which needs a restart of the instance. But the real question comes after enabling the audit options: "Which audit options should we set?". As audit logging is a space consumptive operation it is important for the DBA's to carefully select the options to be logged. Otherwise the SYS.AUD$ table will grow unexpectedly. Moreover this table resides in the SYSTEM tablespace and even after changing the audit options and resizing the table will not help the tablespace to be resized which I dont prefer to have a large SYSTEM tablespace.

In my experience, i always hesitate to enable any DML (insert, delete, update and in this case also select) operation to be logged by database audit on application users (database users used by the application itself or the connection pooling). Depending on the intense usage of the application the DML logging may be disastrous as a lot of log will be produced in th SYS.AUD$ table. But the same DML commands may be logged on developer user accounts which is necessary in most of the cases. Of course enabling these kind of DML operations depends on the application itself or what is being expected from the database audit logs.

On the other hand, auditing DDL (create, drop, alter, truncate) operations should be enabled for auditing regardless of the user and object (Of course this also depends on the application behaviour but still should be forced to be audited).

To find which options to be audited exactly, the following query can be used. Which lists the most important System Privileges to be audited. Any user executing these kind of DML operations should be audited for further security surveillance.


SELECT 
  'audit ' || name || ';'
FROM 
  system_privilege_map
WHERE 
  (  name LIKE 'CREATE%'
  or name LIKE 'ALTER%'
  or name LIKE 'DROP%'
  or name LIKE 'EXECUTE%'
  or name LIKE 'GRANT%'
  or name LIKE 'BACKUP%'
  or name LIKE 'EXPORT%'
  or name LIKE 'IMPORT%'
  or name LIKE 'BECOME%'
  )
order by name;


After executing the output of the above script, enabled system privileges can be seen by selecting from the following dictionary view.


select * from dba_priv_audit_opts;


According to the application behaviour, even with the DML auditing only, application user may produce audit data which cannot be managed. In this case individual users should be audited on the DML operations accept the application user itself. It is as easy as adding "by " at the and of the audit statement.


audit drop any table by D_EPEKER;


Beyond auditing the system privileges, individual objects can also be audited. According to the application behaviour some of the tables may have significant importance and not only auditing the DML operations is sufficient but also the DDL operations should be audited to lower the security risks. As it is very hard to manage the operation of the audit data which will be produced by the application user on all tables, in this case individual database tables can be audited.

Keep in my that object level auditing can be both by session and by access. "By Access" audits every occurance of the event while "By Session" audits only the last occurance of the event within the same session. The decision of the level, again depends on what is expected from the audit logs.


audit update on SYS.T_TEST_TABLE by access;
audit update on SYS.T_TEST_TABLE by session;

select * from dba_obj_audit_opts;


Of course, these are my preferences while setting up the auditing option in oracle database. I usually always set the auditing of the privileges for all users as discussed above and leave the rest to the application developers and analysts as they are more aware of the application logic and the most ciritical objects to be audited.



Monday, September 12, 2011

Random Data Generation and DBMS_RANDOM

Generating random data itself is already a subject of its own. But here i can only write about the needs of random data in a database environment and how a database developer or administrator can generate the random data to fulfill his/her requirements. I personally used random data generation in three main purposes up to now.

DATAMASKING

Almost in every company i have worked for, datamasking is a must-have procedure for test data generation, especially after restoring production data to a prelive or day-1 database. In common sense just truncating the sensitive data or updating the columns to NULL maybe enough for security purposes. But in some individual cases application logic needs to continue which depends on the data availability. In such cases there are two main roadmaps, hashing the real data and un-identify it or some random data may be generated for representing the real sensitive data. The generated data may also ensure the formatting of the known structures such as credit card information, postal code or telephone number of the customers.

PASSWORD GENERATION

After applying the new password policy to our database, forgotten passwords by the end users are not recovered that easily because of the password complexity functions (by applying password verify function) and the password_reuse_max parameter of the profile. This means that, the portal used by the level-1 support is not enough as the procedure lies behind the button is simply changes the password to a default value which is not changed from the beginning of the procedure at all, which causes ORA-28007: the password cannot be reused exception.

TEST DATA GENERATION

In order to test any functionality or any new features by myself, generating data for newly created tables is a necessity. Formatted varchar2 and number columns are very handy to test some functionalities and how some functionalities behave in large amount of structured table data.

Dictionary views can be used for this purpose but If it is not enough for the individual test conditions then generation a random data within the desired format is crucial.

DBMS_RANDOM PACKAGE

For all the mentioned purposes, oracle database has a built-in package which is DBMS_RANDOM to generate random data. There are several functions in this package which can be used to obtain same results with some manipulation of the output values. Main functions to produce random number would be;

DBMS_RANDOM.VALUE() whichs output value is NUMBER datatype, this means you can produce up to 32 digit numbers.


select dbms_random.value() as result from dual;

RESULT
------
0.33363563290178533954768590716355821427


DBMS_RANDOM.VALUE(arg1 number, arg2 number) returns a random value between the supplied limits. The following sql should return a random number between 1 and 20.


select dbms_random.value(1,20) as result from dual;

RESULT
------
14.25291834803147861791906299688905822678


DBMS_RANDOM.STRING() function can also be used in order to generate a random character or a string. Function has two parameters one for the type of characters to be used and the second parameter for the length of the string. The following function definition is copied here from and Oracle 11gR2 databases DBMS_RANDOM package spec. It explains itself very well and nothing needs to be added.


FUNCTION string (opt char, len NUMBER)

/* 
"opt" specifies that the returned string may contain:

'u','U': upper case alpha characters only
'l','L': lower case alpha characters only
'a','A': alpha characters only (mixed case)
'x','X': any alpha-numeric characters 'p','P': any printable characters
*/
RETURN VARCHAR2;  
--string of  characters


So, if you need to produce some random string with 8 characters long and all characters are alpha numeric and lower case then it is easy by using the DBMS_RANDOM.STRING() function:


select dbms_random.string('l',8) as result from dual;

RESULT
------
yhxctomv


DBMS_RANDOM BY EXAMPLES

All the explanations of the examples can be found in the document that i shared from here. You can also find the link at the bottom of this post to the same document.


--------------------------
--masking the card numbers
--Ex.1
--------------------------
select 
lpad(round(dbms_random.value*power(10,4)),4,0) || '-' ||
lpad(round(dbms_random.value*power(10,4)),4,0) || '-' ||
lpad(round(dbms_random.value*power(10,4)),4,0) || '-' ||
lpad(round(dbms_random.value*power(10,4)),4,0)  as card_number
from dual 
connect by level <=5; 
/*
CARD_NUMBER
-----------
2877-6639-0728-5456
6026-6002-2218-9038
7679-8441-0899-2826
8294-6783-6110-7988
1836-0407-9206-3333
*/

--------------------------
--masking the card numbers
--Ex.2
--------------------------
select 
ltrim(to_char(dbms_random.value(1,9999),'0000')) || '-' ||
ltrim(to_char(dbms_random.value(1,9999),'0000')) || '-' ||
ltrim(to_char(dbms_random.value(1,9999),'0000')) || '-' ||
ltrim(to_char(dbms_random.value(1,9999),'0000'))  as card_number
from dual 
connect by level <=5; 
/*
CARD_NUMBER
-----------
1558-9846-7194-5325
5109-3233-0641-9209
3081-5946-9840-6615
4400-9638-6333-9113
2928-9883-1771-0465
*/

--------------------------
--masking the card numbers
--Ex.3
--------------------------
select 
ltrim(replace(to_char(round(dbms_random.value*power(10,16)),'0000,0000,0000,0000'),',','-')) as card_number
from dual
connect by level <=5;
/*
CARD_NUMBER
-----------
0157-8125-6418-6025
3829-9039-1357-9048
2876-1086-5371-8152
2775-1748-2591-2523
2058-2404-1101-5320
*/

--------------------------
--masking the card numbers
--Ex.4
--------------------------
select 
substr(abs(dbms_random.random),1,4) || '-' ||
substr(abs(dbms_random.random),1,4) || '-' ||
substr(abs(dbms_random.random),1,4) || '-' ||
substr(abs(dbms_random.random),1,4)  as card_number
from dual 
connect by level <=5; 
/*
CARD_NUMBER
-----------
8639-7576-1359-3965
1317-1525-2526-1796
1043-5881-1000-7113
2106-3239-8662-3769
1461-7473-5870-6829
*/

--------------------------
--masking the phone number
--Ex.5
--------------------------
select 
  '+' || 
  round(DBMS_RANDOM.VALUE(1,99)) || '-' ||
  round(DBMS_RANDOM.VALUE(10,99)) || '-' ||
  round(DBMS_RANDOM.VALUE(1000000,9999999)) as phone_number
from dual
connect by level <= 5;
/*
PHONE_NUMBER
------------
+8-44-9146987
*/

----------------------
--masking the postcode
--Ex.6
----------------------
select 
  round(dbms_random.value(1000,9999)) || '-' || 
  dbms_random.string('U',2) as postcode 
from dual;
/*
POSTCODE
--------
4997-QP
*/



What if, you have a password verify function which commits the passwords will be at least 8 characters long and must contain alphanumeric characters and this password complexity merged with a profile which has a password_lifetime of two month and password_reuse_max is four. If there is a predefined automatic case which explained detailly in the paper mentioned before which needs random password generation then there is the example which can be used;

-----------------
--random password
--Ex.7
-----------------
select  
  DBMS_RANDOM.STRING('A',1) || 
  round(DBMS_RANDOM.VALUE()*10) || 
  DBMS_RANDOM.STRING('X',6) as password 
from dual;
/*
PASSWORD
--------
w7N3C1YG
*/


TEST DATA GENERATION

I generally use two different methods while generating test data to fill the test tables. One of them is by using the DBMS_RANDOM package and the other is filling the bulk data in the columns with the same output as you can find in the following examples.

In this first part of the following example, the code tries to simulate a username bu using lower case string and with random lengths between five and fifteen. The firstname starts with uppercase by using INICAP() function and the lastname is fully in uppercase by using the UPPER() inline function. The second part is not that clever and it just creates the same data over and over which can substitude a customer name or a username.

----------------------
--test data generation
--Ex.8
----------------------
select 
  initcap(dbms_random.string('L',round(dbms_random.value(5,15)))) || ' ' || 
  upper(dbms_random.string('L',round(dbms_random.value(5,15)))) as name
from dual
connect by level <= 5;
/*
NAME
----
Abzvsidgbcfa AGUGIR
Wvuogptkxwhdwa IPOOXTVBLLCNPV
Yiwcgh SGPFKJYCDISO
Radshiyidcrst ZNKNSEYUZXVWY
Daxeqzugq LKJILZJEYULVI
*/

select
initcap(lpad('x',round(dbms_random.value(5,15)),'x')) || ' ' || 
upper(lpad('y',round(dbms_random.value(5,15)),'y')) as name
from dual
connect by level <= 5;
/*
NAME
----
Xxxxxxxxxxxx YYYYYYYYYYY
Xxxxxxxxxxxxxxx YYYYYYYYYYYYY
Xxxxxxxxxxxxxx YYYYYYYYY
Xxxxxxxx YYYYYYYYYYY
Xxxxxx YYYYYYYY
*/


select 
  initcap(lpad('x',9,'x')) || ' ' ||
  upper(lpad('y',9,'y')) as name
from dual
connect by level <= 5;
/*
NAME
----
Xxxxxxxxx YYYYYYYYY
Xxxxxxxxx YYYYYYYYY
Xxxxxxxxx YYYYYYYYY
Xxxxxxxxx YYYYYYYYY
Xxxxxxxxx YYYYYYYYY
*/


GENERATING MEANINGFUL DATA

Upto now, the generated data was completely dummy. For example while masking the credit card number, it wasn’t important if this was a valid card number or not, or if the names are real names or not. All the data generated were dummy random data which does not make any sense, they are just string or numbers formed by number characters or digits.

But by using the following example random data can be generated which makes sense (or a little sensible than the previous methods).

In this small example, there is a lookup table (which can be extended as far as the individual case needs) and the phone number generator picks up a random country code from the lookup table to generate the phone number. Every random phone number generated will have a valid country code by using the following example. Of course this example can be extended for the area codes as well.

--------------------------
--generating sensible data
--Ex.9
--------------------------
create table t_country_codes 
  (key number(2), 
   code number(2), 
   country varchar2(20));
   
insert into t_country_codes values (1,1,'United States');
insert into t_country_codes values (2,31,'Netherlands');
insert into t_country_codes values (3,44,'United Kingdom');
insert into t_country_codes values (4,49,'Germany');
insert into t_country_codes values (5,90,'Turkey');
commit;

select 
  '+' || code || '-' || 
  round(dbms_random.value(10,99)) || '-' || 
  round(DBMS_RANDOM.VALUE(100000,999999)) as phone_number
from 
  t_country_codes 
where 
  key=(select round(DBMS_RANDOM.VALUE(1,5)) from dual);
/*  
PHONE_NUMBER
------------
+31-54-732777
*/  


This post is taken from the paper i wrote for an internal use and enchanced for my blog post. You can download the paper from the following link if you have google docs access. Generating Random Data in Oracle 11g Database

Tuesday, July 19, 2011

Hasty DBA's Most Probable Errors while testing TDE

Here I tested Oracle Transparent Data Encryption in 10gR2 (10.2.0.4) database which is installed on AIX 6.1 to see how it works and if there are some undocumented difficulty while using the technology. As i was too hasty and careless, i have seen most of the cheap errors.

In Summary;

ORA-28368: cannot auto-create wallet

Solution: Create the wallet directory (in this case default wallet directory which is $ORACLE_BASE/admin/$ORACLE_SID/wallet)

ORA-28336: cannot encrypt SYS owned objects

Solution: Do not test under SYS schema :)

ORA-39173: Encrypted data has been stored unencrypted in dump file set.

Solution: Use encryption_password parameter to store encrypted data safe in the export dump. Else it will be plain text.

ORA-31693: Table data object "ERGEMP"."T_ENCRYPTED" failed to load/unload and is being skipped due to error:
ORA-28336: cannot encrypt SYS owned objects

Solution: Use your own user for exporting instead of SYS as you cannot encrypt SYS obejcts even in the export dumpfile.

Error: ORA-39087: directory name DATA_PUMP_DIR is invalid

Solution: Dont forget to give write permission to your user which you are exporting data with :)


The rest is as follows.


[oracle@defbora01]:/oracle/admin/CORET > sql

SQL*Plus: Release 10.2.0.4.0 - Production on Thu Jul 14 12:18:08 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> alter system set encryption key identified by "pass1234";
alter system set encryption key identified by "pass1234"
*
ERROR at line 1:
ORA-28368: cannot auto-create wallet


SQL> exit
Disconnected from Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
[oracle@defbora01]:/oracle/admin/CORET > mkdir wallet
[oracle@defbora01]:/oracle/admin/CORET > sql

SQL*Plus: Release 10.2.0.4.0 - Production on Thu Jul 14 12:20:03 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> alter system set encryption key identified by "pass1234";

System altered.

SQL> 


/*** ***/

SQL> create table t_encrypted(col1 varchar2(50) encrypt);
create table t_encrypted(col1 varchar2(50) encrypt)
*
ERROR at line 1:
ORA-28336: cannot encrypt SYS owned objects
SQL> create user ergemp identified by "pass1234" default tablespace users;

User created.

SQL> 
SQL> 
SQL> grant connect, resource to ergemp;

Grant succeeded.

SQL> create table ergemp.t_encrypted(col1 varchar2(50) encrypt);

Table created.

SQL> insert into ergemp.t_encrypted values ('this text should be encrypted');

1 row created.

SQL> commit;

Commit complete.

SQL> select * from dba_encrypted_columns;

OWNER           TABLE_NAME                     COLUMN_NAME               ENCRYPTION_ALG                SAL
--------------- ------------------------------ ------------------------- ----------------------------- ---
ERGEMP          T_ENCRYPTED                    COL1                      AES 192 bits key              YES

SQL> select * from ERGEMP.T_ENCRYPTED;

COL1
--------------------------------------------------
this text should be encrypted

SQL> 



I will test the datapump export. First i will not use the "encryption_password" parameter and search for the string of the column value if it is somewhere in the dumpfile.

And then i will run the same datapump export by using the "encryption_password" parameter to be sure the column value is not readable in the dumpfile with "string" utility.


[oracle@defbora01]:/oracle/orahome1/rdbms> expdp '/******** AS SYSDBA' directory=DATA_PUMP_DIR dumpfile=expdp.dmp logfile=expdp.log tables='ERGEMP.T_ENCRYPTED'


Export: Release 10.2.0.4.0 - 64bit Production on Friday, 15 July, 2011 11:53:18

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

Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Starting "SYS"."SYS_EXPORT_TABLE_01":  '/******** AS SYSDBA' directory=DATA_PUMP_DIR dumpfile=expdp.dmp logfile=expdp.log tables=ERGEMP.T_ENCRYPTED 
Estimate in progress using BLOCKS method...
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 64 KB
Processing object type TABLE_EXPORT/TABLE/TABLE
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
. . exported "ERGEMP"."T_ENCRYPTED"                      4.953 KB       1 rows
ORA-39173: Encrypted data has been stored unencrypted in dump file set.
Master table "SYS"."SYS_EXPORT_TABLE_01" successfully loaded/unloaded
******************************************************************************
Dump file set for SYS.SYS_EXPORT_TABLE_01 is:
/oracle/orahome1/rdbms/log/expdp.dmp
Job "SYS"."SYS_EXPORT_TABLE_01" completed with 1 error(s) at 11:56:53

[oracle@defbora01]:/oracle/orahome1/rdbms/log > strings expdp.dmp | grep "this text should be encrypted"
this text should be encrypted

[oracle@defbora01]:/oracle/orahome1/rdbms/log >



Without using the "encryption_password", data in the export files are not safe because the they are held as in plain text as it can be seen from the previous example.


[oracle@defbora01]:/oracle/orahome1/rdbms> expdp '/******** AS SYSDBA' directory=DATA_PUMP_DIR dumpfile=expdp.dmp logfile=expdp.log tables='ERGEMP.T_ENCRYPTED' encryption_password="pass1234"

Export: Release 10.2.0.4.0 - 64bit Production on Friday, 15 July, 2011 13:53:56

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

Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Starting "SYS"."SYS_EXPORT_TABLE_01":  '/******** AS SYSDBA' directory=DATA_PUMP_DIR dumpfile=expdp.dmp logfile=expdp.log tables=ERGEMP.T_ENCRYPTED encryption_password=******** 
Estimate in progress using BLOCKS method...
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 64 KB
Processing object type TABLE_EXPORT/TABLE/TABLE
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
ORA-31693: Table data object "ERGEMP"."T_ENCRYPTED" failed to load/unload and is being skipped due to error:
ORA-28336: cannot encrypt SYS owned objects
Master table "SYS"."SYS_EXPORT_TABLE_01" successfully loaded/unloaded
******************************************************************************
Dump file set for SYS.SYS_EXPORT_TABLE_01 is:
/oracle/orahome1/rdbms/log/expdp.dmp
Job "SYS"."SYS_EXPORT_TABLE_01" completed with 1 error(s) at 13:55:55

[oracle@defbora01]:/oracle/orahome1/rdbms> expdp 'ergemp/********' directory=DATA_PUMP_DIR dumpfile=expdp.dmp logfile=expdp.log tables='ERGEMP.T_ENCRYPTED' encryption_password="pass1234"

Export: Release 10.2.0.4.0 - 64bit Production on Friday, 15 July, 2011 13:59:17

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

Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
ORA-39002: invalid operation
ORA-39070: Unable to open the log file.
ORA-39087: directory name DATA_PUMP_DIR is invalid

SQL> grant read,write on directory DATA_PUMP_DIR to ERGEMP;

Grant succeeded.

[oracle@defbora01]:/oracle/orahome1/rdbms> expdp 'ergemp/********' directory=DATA_PUMP_DIR dumpfile=expdp.dmp logfile=expdp.log tables='ERGEMP.T_ENCRYPTED' encryption_password="pass1234"

Export: Release 10.2.0.4.0 - 64bit Production on Friday, 15 July, 2011 14:08:59

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

Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Starting "ERGEMP"."SYS_EXPORT_TABLE_01":  'ergemp/********' directory=DATA_PUMP_DIR dumpfile=expdp.dmp logfile=expdp.log tables=ERGEMP.T_ENCRYPTED encryption_password=******** 
Estimate in progress using BLOCKS method...
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 64 KB
Processing object type TABLE_EXPORT/TABLE/TABLE
Processing object type TABLE_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
. . exported "ERGEMP"."T_ENCRYPTED"                          5 KB       1 rows
Master table "ERGEMP"."SYS_EXPORT_TABLE_01" successfully loaded/unloaded
******************************************************************************
Dump file set for ERGEMP.SYS_EXPORT_TABLE_01 is:
/oracle/orahome1/rdbms/log/expdp.dmp
Job "ERGEMP"."SYS_EXPORT_TABLE_01" successfully completed at 14:10:19

[oracle@defbora01]:/oracle/orahome1/rdbms/log > strings expdp.dmp | grep "this text should be encrypted"

[oracle@defbora01]:/oracle/orahome1/rdbms/log >



By using the "encryption_password" while exporting the table the data in the column cannot be distinguished by digging the plain strings in the export file.

resources:
Oracle Advanced Security Admin Guide

Thursday, June 16, 2011

The way of opatch 10.2.0.4 Database on AIX


[oracle@]:/oracle/asmhome1/OPatch > opatch version
Invoking OPatch 10.2.0.5.1

OPatch Version: 10.2.0.5.1

OPatch succeeded.

[oracle@]:/oracle/asmhome1/OPatch > cd
[oracle@]:/oracle > . .profile

[oracle@]:/oracle > sql

SQL*Plus: Release 10.2.0.4.0 - Production on Wed Jun 1 09:48:52 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> alter system checkpoint;

System altered.

SQL> shutdown abort;
ORACLE instance shut down.
SQL> exit
Disconnected from Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

[oracle@]:/oracle > 
[oracle@]:/oracle > . .profile_asm
[YOU HAVE NEW MAIL]
[oracle@]:/oracle > sql

SQL*Plus: Release 10.2.0.4.0 - Production on Wed Jun 1 09:54:58 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> shutdown;
ASM diskgroups dismounted
ASM instance shutdown
SQL> exit
Disconnected from Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
[oracle@]:/oracle > lsnrctl stop

LSNRCTL for IBM/AIX RISC System/6000: Version 10.2.0.4.0 - Production on 01-JUN-2011 09:49:09

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

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=defbora01)(PORT=1521)))
The command completed successfully

[oracle@]:/oracle/orahome1/OPatch > su - 
root's Password: 
[root@]:/home/root> /usr/sbin/slibclean
[root@]:/home/root>

[oracle@]:/oracle > cd $ORACLE_HOME/OPatch
[oracle@]:/oracle/asmhome1/OPatch > ls
11725015                              jlib                                  opatch.pl
README.txt                            ocm                                   opatchprereqs
crs                                   opatch                                p11725015_10204_AIX5L-cpuapr2011.zip
docs                                  opatch.bat                            p6880880_102000_AIX64-5L-opatch.zip
emdpatch.pl                           opatch.ini
[oracle@]:/oracle/asmhome1/OPatch > cd 11725015 
[oracle@]:/oracle/asmhome1/OPatch/11725015 > opatch napply --skip_subset --skip_duplicate

... 
(output truncated)
...

--------------------------------------------------------------------------------
**********************************************************************
**                       ATTENTION                                  **
**                                                                  **
** Please note that this Patch Installation is                      **
** not complete until all the Post Installation instructions        **
** noted in the Readme accompanying this patch, have been           **
** successfully completed.                                          **
**                                                                  **
**********************************************************************

--------------------------------------------------------------------------------


The local system has been patched and can be restarted.

UtilSession: N-Apply done.

OPatch succeeded.

[oracle@]:/oracle/asmhome1/OPatch/11725015 > 
[oracle@]:/oracle/asmhome1/OPatch/11725015 > opatch lsinv

... 
(output truncated)
...

[oracle@]:/oracle > . .profile
[oracle@]:/oracle/orahome1/OPatch > cd 11725015 
[oracle@]:/oracle/orahome1/OPatch/11725015 > opatch napply --skip_subset --skip_duplicate

...
(output truncated)
...

[oracle@]:/oracle/orahome1/OPatch/11725015 > sql

SQL*Plus: Release 10.2.0.4.0 - Production on Wed Jun 1 10:20:14 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

Connected to an idle instance.

SQL> startup upgrade;
ORACLE instance started.

Total System Global Area 3221225472 bytes
Fixed Size                  2087480 bytes
Variable Size             637535688 bytes
Database Buffers         2566914048 bytes
Redo Buffers               14688256 bytes
Database mounted.
Database opened.
SQL> @?/rdbms/admin/catbundle.sql cpu apply
SQL> @?/rdbms/admin/utlrp.sql

[oracle@]:/oracle/orahome1/cpu/view_recompile > ls -l
total 24
-rwxr-xr-x    1 oracle   dba            2095 Jul 10 2008  recompile_precheck_jan2008cpu.sql
-rwxr-xr-x    1 oracle   dba            5143 Jul 10 2008  view_recompile_jan2008cpu.sql
[oracle@]:/oracle/orahome1/cpu/view_recompile > sql

SQL*Plus: Release 10.2.0.4.0 - Production on Wed Jun 1 10:34:16 2011

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> @recompile_precheck_jan2008cpu.sql;

Running precheck.sql...

Number of views to be recompiled :2226
-----------------------------------------------------------------------

Number of objects to be recompiled :4347
Please follow the README.txt instructions for running viewrecomp.sql

PL/SQL procedure successfully completed.

SQL> @view_recompile_jan2008cpu.sql;

PL/SQL procedure successfully completed.


PL/SQL procedure successfully completed.


PL/SQL procedure successfully completed.


1 row created.


Commit complete.

No. of Invalid Objects is :1848
Please refer to README.html to for instructions on validating these objects

PL/SQL procedure successfully completed.

Logfile for the current viewrecomp.sql session is : vcomp_CORET_01Jun2011_11_47_53.log
SQL> shutdown immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup;
ORACLE instance started.

Total System Global Area 3221225472 bytes
Fixed Size                  2087480 bytes
Variable Size             637535688 bytes
Database Buffers         2566914048 bytes
Redo Buffers               14688256 bytes
Database mounted.
Database opened.
SQL> 

SQL> select bundle_series, action, version from dba_registry_history;

BUNDLE_SERIES          ACTION  VERSION
---------------------- ---------------- --------
CPU                    APPLY CPU 10.2.0.4


SQL> SELECT * FROM registry$history where ID = '6452863';

SQL> select bundle_series, action, version from registry$history where ID = '6452863';

BUNDLE_SERIES                  ACTION     VERSION
------------------------------ ---------- ------------------------------
CPU

Sunday, December 14, 2008

why auditing

In general it seems that security is one of the least important routines of the dba. But in my opinion this issue should be one of the most important issues. Not only be able to supply audit records to firm-wide audit documentations but also knowing what is going on our databases to be sure everything goes straight. Auditing is not only blaming someone for a wrong action. This routine is for early clearing up for the wrong events.
I start auditing with "db, extended" AUDIT_TRAIL parameter to track the sql statements with the actions by altering the system, restarting the instance is a must as this parameter cannot be changed online:

SQL> alter system set audit_trail="db, extended" scope=spfile;
SQL> shutdown immediate;
SQL> startup;

After enabling the auditing, i decided what actions should be audited. Here i was not very selective, i simply enabled all DML actions for the individual users.

AUDIT 
  INSERT ANY TABLE, 
  DELETE ANY TABLE, 
  UPDATE ANY TABLE 
BY "username" ;

AUDIT 
  INSERT TABLE, 
  DELETE TABLE, 
  UPDATE TABLE 
BY "username" ;

AUDIT 
  DROP ANY TABLE, 
  DROP ANY INDEX, 
  DROP ANY VIEW, 
  DROP ANY SYNONYM, 
  DROP ANY PROCEDURE, 
  DROP ANY SEQUENCE, 
  DROP ANY TRIGGER, 
  DROP ANY TYPE 
BY "username" ;

AUDIT 
  ALTER ANY TABLE, 
  ALTER ANY INDEX, 
  ALTER ANY PROCEDURE, 
  ALTER ANY SEQUENCE, 
  ALTER ANY TRIGGER, 
  ALTER ANY TYPE 
BY "username" ;

AUDIT 
  CREATE ANY TABLE, 
  DROP ANY INDEX, 
  DROP ANY VIEW, 
  DROP ANY SYNONYM, 
  DROP ANY PROCEDURE, 
  DROP ANY SEQUENCE, 
  DROP ANY TRIGGER, 
  DROP ANY TYPE 
BY "username";

Move sys.aud$ table to data tablespace: We dont want to oversize the SYSTEM tablespace. As far as i read from oracle documentation moving AUD$ table to another tablespace is not supported. Instead of this action writing some control and maintenance scripts are suggested to be used.

select * from sys.AUD$;
alter table sys.AUD$ move tablespace PQ_DATA;

List the auditing privileges and users: To check what is being audited by my database.
select * from dba_priv_audit_opts;
After two weeks of auditing, i nearly captured more than three commonly wrong routines especially using wrong tablespaces and deleting routines.


Monday, November 3, 2008

Time to start securing the listeners

I decided to apply basic security issues to all of my databases listener processes. As always i prefer Oracle Documentation for a reliable reference, this time i found a detailed white paper on integrigy web site which has a lot of hits from external links.

Both two resources call attention for two most important issues. Setting a password and Logging for the listener. The other issues can be taken in account are securing lsnrctl and tnslsnr executables in $ORACLE_HOME/bin/ directory, setting ADMIN_RESTRICTIONS parameter of the listener itself, changing default port of the listener utility and so on mentioned in the referenced documents. But here i decided to secure most common tasks of setting a password for listener and logging the listener activity for my initial action.

Setting a listener password:

-bash-3.00$ lsnrctl

LSNRCTL for Linux: Version 10.2.0.3.0 - Production on 03-NOV-2008 14:06:01

Copyright (c) 1991, 2006, Oracle. All rights reserved.

Welcome to LSNRCTL, type "help" for information.

LSNRCTL> CHANGE_PASSWORD
Old password: <if not set then just hit enter>
New password:
Reenter new password:
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=foa-op)(PORT=1521)))
Password changed for LISTENER
The command completed successfully
LSNRCTL> SAVE_CONFIG
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=foa-op)(PORT=1521)))
Saved LISTENER configuration parameters.
Listener Parameter File /oracle/product/10.2.0/OFADB/network/admin/listener.ora
Old Parameter File /oracle/product/10.2.0/OFADB/network/admin/listener.bak
The command completed successfully
LSNRCTL> status
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=foa-op)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 10.2.0.3.0 - Production
Start Date 03-NOV-2008 11:12:23
Uptime 0 days 2 hr. 54 min. 43 sec
Trace Level off
Security ON: Password or Local OS Authentication
SNMP OFF
Listener Parameter File /oracle/product/10.2.0/OFADB/network/admin/listener.ora
Listener Log File /oracle/product/10.2.0/OFADB/network/log/listener.log
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=foa-op)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC0)))
Services Summary...
Service "OFADB" has 1 instance(s).
Instance "OFADB", status READY, has 1 handler(s) for this service...
Service "OFADBXDB" has 1 instance(s).
Instance "OFADB", status READY, has 1 handler(s) for this service...
Service "OFADB_XPT" has 1 instance(s).
Instance "OFADB", status READY, has 1 handler(s) for this service...
Service "PLSExtProc" has 1 instance(s).
Instance "PLSExtProc", status UNKNOWN, has 1 handler(s) for this service...
The command completed successfully
LSNRCTL> exit


Logging the listener:

-bash-3.00$ lsnrctl

LSNRCTL for Linux: Version 10.2.0.3.0 - Production on 03-NOV-2008 11:18:43

Copyright (c) 1991, 2006, Oracle. All rights reserved.

Welcome to LSNRCTL, type "help" for information.

LSNRCTL> SET LOG_DIRECTORY /oracle/product/10.2.0/OFADB/network/admin/lsnr_log
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=foa-op)(PORT=1521)))
LISTENER parameter "log_directory" set to /oracle/product/10.2.0/OFADB/network/admin/lsnr_log
The command completed successfully
LSNRCTL> set log_file lsnr.log
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=foa-op)(PORT=1521)))
LISTENER parameter "log_file" set to lsnr.log
The command completed successfully
LSNRCTL> set log_status on
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=foa-op)(PORT=1521)))
LISTENER parameter "log_status" set to ON
The command completed successfully
LSNRCTL> SAVE_CONFIG
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=foa-op)(PORT=1521)))
Saved LISTENER configuration parameters.
Listener Parameter File /oracle/product/10.2.0/OFADB/network/admin/listener.ora
Old Parameter File /oracle/product/10.2.0/OFADB/network/admin/listener.bak
The command completed successfully
LSNRCTL> exit
-bash-3.00$ lsnrctl status

LSNRCTL for Linux: Version 10.2.0.3.0 - Production on 03-NOV-2008 11:20:08

Copyright (c) 1991, 2006, Oracle. All rights reserved.

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=foa-op)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 10.2.0.3.0 - Production
Start Date 03-NOV-2008 11:12:23
Uptime 0 days 0 hr. 7 min. 44 sec
Trace Level off
Security ON: Password or Local OS Authentication
SNMP OFF
Listener Parameter File /oracle/product/10.2.0/OFADB/network/admin/listener.ora
Listener Log File /oracle/product/10.2.0/OFADB/network/admin/lsnr_log/lsnr.log
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=foa-op)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC0)))
Services Summary...
Service "OFADB" has 1 instance(s).
Instance "OFADB", status READY, has 1 handler(s) for this service...
Service "OFADBXDB" has 1 instance(s).
Instance "OFADB", status READY, has 1 handler(s) for this service...
Service "OFADB_XPT" has 1 instance(s).
Instance "OFADB", status READY, has 1 handler(s) for this service...
Service "PLSExtProc" has 1 instance(s).
Instance "PLSExtProc", status UNKNOWN, has 1 handler(s) for this service...
The command completed successfully


But while i was monitoring the log file of the listener i found some warning messages right before every server process created by listener. The warning is something like;

WARNING: Subscription for node down event still pending


There are some comments on forums for this warning message but the general sentence is setting the

SUBSCRIBE_FOR_NODE_DOWN_EVENT_<listener_name>


parameter to OFF in listener.ora file. By disabling this option we prevent listener to automatically registers itself to a notification service as it is unsuccessful to do because there is not one installed. Setting this parameter to OFF is worked for my environment and warning messages are cleared. Following you can find my final listener.ora file.


-bash-3.00$ cat listener.ora

SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = PLSExtProc)
(ORACLE_HOME = /oracle/product/10.2.0/OFADB)
(PROGRAM = extproc)
)
)

LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = xxx-xx)(PORT = xxxx))
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC0))
)
)

#----ADDED BY TNSLSNR 03-NOV-2008 11:08:38---
PASSWORDS_LISTENER = xxxxxxxxxxxxxxxx
LOGGING_LISTENER = ON
#--------------------------------------------

#----ADDED BY TNSLSNR 03-NOV-2008 11:19:57---
LOG_FILE_LISTENER = lsnr.log
LOG_DIRECTORY_LISTENER = /oracle/product/10.2.0/OFADB/network/admin/lsnr_log
#--------------------------------------------

SUBSCRIBE_FOR_NODE_DOWN_EVENT_LISTENER=OFF


Another handy operation of setting the password for the listener is remote administration option. The following demonstration is from my client computer to administer the server listener remotely. In a nutshell if you now the ip and port that the listeners runs on and also know the password, then you can remotely administer you listener.


Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\>lsnrctl status 10.4.38.32:1521

LSNRCTL for 32-bit Windows: Version 10.2.0.1.0 - Production on 03-NOV-2008 14:36:02

Copyright (c) 1991, 2005, Oracle. All rights reserved.

Connecting to (DESCRIPTION=(CONNECT_DATA=(SERVICE_NAME=10.4.38.32))(ADDRESS=(PRO
TOCOL=TCP)(HOST=10.4.38.32)(PORT=1521)))
TNS-01169: The listener has not recognized the password
TNS-01189: The listener could not authenticate the user

C:\>lsnrctl

LSNRCTL for 32-bit Windows: Version 10.2.0.1.0 - Production on 03-NOV-2008 14:36:05

Copyright (c) 1991, 2005, Oracle. All rights reserved.

Welcome to LSNRCTL, type "help" for information.

LSNRCTL> set password
Password:
The command completed successfully
LSNRCTL> status 10.4.38.32:1521
Connecting to (DESCRIPTION=(CONNECT_DATA=(SERVICE_NAME=10.4.38.32))(ADDRESS=(PRO
TOCOL=TCP)(HOST=10.4.38.32)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 10.2.0.3.0 - Production
Start Date 03-NOV-2008 11:12:23
Uptime 0 days 3 hr. 24 min. 0 sec
Trace Level off
Security ON: Password or Local OS Authentication
SNMP OFF
Listener Parameter File /oracle/product/10.2.0/OFADB/network/admin/listener.ora
Listener Log File /oracle/product/10.2.0/OFADB/network/admin/lsnr_log/lsnr.log
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=foa-op)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC0)))
Services Summary...
Service "OFADB" has 1 instance(s).
Instance "OFADB", status READY, has 1 handler(s) for this service...
Service "OFADBXDB" has 1 instance(s).
Instance "OFADB", status READY, has 1 handler(s) for this service...
Service "OFADB_XPT" has 1 instance(s).
Instance "OFADB", status READY, has 1 handler(s) for this service...
Service "PLSExtProc" has 1 instance(s).
Instance "PLSExtProc", status UNKNOWN, has 1 handler(s) for this service...
The command completed successfully
LSNRCTL>

Monday, May 26, 2008

A Security Hardening Approach for userproof databases

What if you have some confusion about some of your database users and want to trace the users or even be notified about their actions in the database or just want to warn them about probable mistakes can be made by db users. Oracle Database software has some solutions about likely cases. Auditing is one of the most used option with tracing. DDL triggers can also be used. There are also some solutions at the opsys level.

1- Logon Triggers to Trace Users
Oracle database has logon triggers to run on any users login to the database. DBA can use this feature to set a trace file for the logged in user. tkprof utility can be used to examine users activity.

CREATE OR REPLACE TRIGGER SYS.TRG_SESSION_LOGON after logon on database
declare
s_username varchar2(20);
s_sessid varchar2(20);
s_stamp varchar2(20);
begin

-- obtain sid of the session
select distinct(substr(sid,1,20)) into s_sessid from v$mystat;

-- obtain username of the session
select username into s_username from v$session where sid=s_sessid;

-- create a timestamp to uniquely identify the trace file
select to_char(sysdate,'DDMMYYYY_HH24MISS') into s_stamp from dual;

-- set the tracefile size to unlimited. careful about that (!)
execute immediate 'alter session set max_dump_file_size=unlimited';

-- define an identifier to the tracefile to distinguish the trace files
execute immediate 'alter session set tracefile_identifier=' || s_username ||
'_' || s_sessid || '_' || s_stamp;

-- i will take 10046 trace level 8 to see the waits
-- (check timed_statistics init parameter!)
execute immediate 'alter session set events ''10046 trace name context forever, level 8''';

-- finally start the trace
execute immediate 'alter session set sql_trace=true';

exception
when others then
raise;

end TRG_LOGON;

You can find the trace files from user_dump_dest parameter

SQL> show parameter user_dump_dest;

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
user_dump_dest string D:\ORACLEDB10G\ADMIN\ORCL\UDUMP

To examine the dump file tkprof utility can be used.

tkprof orcl_ora_5412_epeker_148_22052008_162752.trc tkprof.out

tkprof.out file.

2- Database Audit
To enable audit option, audit_trail init parameter should be set.

select name, value from v$parameter where name = 'audit_trail';
alter system set audit_trail='DB_EXTENTED' scope=spfile;
--After changing audit_trail parameter bounce the database.

audit select table, insert table, update table, delete table by epeker;
audit session by epeker;


Now login to the database with the audited user and make some ddl.

select * from EPEKER.T_TABLE_DBA_TABLES;
insert into EPEKER.T_TABLE_DBA_TABLES select * from DBA_TABLES where rownum<10;
commit;
select * from EPEKER.T_TABLE_DBA_TABLES;


All the audit information should be in the SYS.AUD$ table

select
SESSIONID, USERID, USERHOST,TERMINAL, OBJ$CREATOR, OBJ$NAME, NTIMESTAMP#, SCN, SQLTEXT
from
SYS.AUD$
order by NTIMESTAMP# desc;


/*
SESSIONID USERID OBJ$CREATOR OBJ$NAME NTIMESTAMP# SCN SQLTEXT
1249 EPEKER SYS, USER$ 5/23/2008 11:45:00 AM 935996 insert into EPEKER.T_TABLE_DBA_TABLES select * from DBA_TABLES where rownum<10
1249 EPEKER SYS, TS$ 5/23/2008 11:45:00 AM 935996 insert into EPEKER.T_TABLE_DBA_TABLES select * from DBA_TABLES where rownum<10
1249 EPEKER SYS, SEG$ 5/23/2008 11:45:00 AM 935996 insert into EPEKER.T_TABLE_DBA_TABLES select * from DBA_TABLES where rownum<10
1249 EPEKER SYS, X$KSPPCV 5/23/2008 11:45:00 AM 935996 insert into EPEKER.T_TABLE_DBA_TABLES select * from DBA_TABLES where rownum<10
1249 EPEKER SYS, TAB$ 5/23/2008 11:45:00 AM 935996 insert into EPEKER.T_TABLE_DBA_TABLES select * from DBA_TABLES where rownum<10
1249 EPEKER SYS, OBJ$ 5/23/2008 11:45:00 AM 935996 insert into EPEKER.T_TABLE_DBA_TABLES select * from DBA_TABLES where rownum<10
1249 EPEKER SYS, DBA_TABLES 5/23/2008 11:45:00 AM 935996 insert into EPEKER.T_TABLE_DBA_TABLES select * from DBA_TABLES where rownum<10
1249 EPEKER SYS, X$KSPPI 5/23/2008 11:45:00 AM 935996 insert into EPEKER.T_TABLE_DBA_TABLES select * from DBA_TABLES where rownum<10
1249 EPEKER EPEKER, T_TABLE_DBA_TABLES 5/23/2008 11:44:10 AM 935944 select * from T_TABLE_DBA_TABLES
1268 EPEKER 5/23/2008 12:01:56 PM
*/

You can revoke the audit by noaudit command.

noaudit select table, insert table, update table, delete table by epeker;
noaudit session by epeker;


3- DDL Triggers
Oracle database has many different trigger options. You have just read about "logon triggers". There is also ddl triggers can be used to disable specific users from mistakenly running dangerous ddl statements. Any user wants to execute a ddl statment (create, truncate.. etc) can be logged and the user can also be warned by the administrator. The following trigger simply disables a user to drop and/or truncate database tables.

CREATE OR REPLACE TRIGGER SYS.TRG_DDL before ddl
ON DATABASE
declare
s_sysevent varchar2(32);
s_owner varchar2(32);
s_objname varchar2(32);
s_user varchar2(32);
begin

select ora_sysevent, ora_dict_obj_owner, ora_dict_obj_name, USER
into s_sysevent, s_owner, s_objname, s_user from dual;

insert into epeker.t_trg_ddl_test values (ora_sysevent);
if s_sysevent in ('DROP','TRUNCATE') then
if s_user = 'EPEKER' then
raise_application_error(-20010,'You are not authorized to drop a segment!.. ');
null;
end if;
end if;

end TRG_DDL;


4- database privileges
Privileges is important (maybe the most important) checklist to be careful about. Privileges and Roles should be carefully assgined and also revoked from users to minimize the mistakenly made data loss in the databases.

5- opsys suggested tasks (alias, sudo, execute privileges, op.sys groups)
Beside database auditing tasks, some securtiy hardening can be made in operating system side. Aliases can be used as of direct op. sys. commands for auditing and preventing mistakes by end users or application users. Some commands need root privileges, this kind of commands can be run through sudo in unix. Application users should not be in dba group and Oracle Home and datafiles should be protected with op. sys. file permissions. Grid agent like management and monitoring tools can be used to audit or proactively solve the likely problems.