OraTOtP ( Oracle Time-based One-time Password )

This post is also available in: Português

OraTOtP

OraTOtP ( Oracle Time-based One-time Password ) is a free tool that adds 2-Factor Authentication layer as an extra security when allowing users to execute anything inside your Oracle Database.

Usage examples of OraTOtP:

  • Add an extra security layer for your database users, making the user password less powerful.
  • If someone discovers any schema password, he will have limited or no access to the DB objects.
  • You want to meet some compliance requirement (e.g.: PCI DSS Requirement 8.3)

Tested on all Oracle Database versions (SE and EE) from 10gR2 until latest 12c.

1. How it Works

After the user connects, his roles will be disabled and the only way to enable them is typing a correct 6-digits token that is generated using a mobile app. The DBA can easily define which roles are required to have 2-Factor Authentication before they get enabled by someone.

OraTOtP tool is intended to be very easy to setup and use, not requiring any major skills for anyone to enable it.

You should not enable 2-Factor Authentication for roles used by logins with unattended access (application, batch jobs, etc) unless there is some application interface to type the token. It is also not recommended to enable it on default roles (DBA, RESOURCE, etc.) as it may impact internal Oracle processes, the most appropriate is that clone these roles with another name and enable this protection.

2. Features

  • If you always connect from the same application and machine, you can ask the tool to trust it for 7 days. So you won't need to type the token again if  you connect on the database from the exactly same place.
  • User can reconfigure the 2-Factor if changing phone or app.
  • Protection against tokens brute-force attacks.
  • The token seed is stored encrypted inside the database. User can provide a password for the encryption seed to make it irreversible by anyone (not even me).

3. Instructions

1- Download an Authenticator app for your mobile. I recommend "Google Authenticator", as it is free, simple and stable:

  • Android: https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2
  • iOS: https://itunes.apple.com/br/app/google-authenticator/id388497605
  • Windows Phone: https://www.microsoft.com/en-us/store/p/authenticator/9wzdncrfj3rj

There are also tons of other Third-Party apps that are based on the same TOTP algorithm.

2- Install OraTOtP tool in your database (check "Installation" section for more details).

3- CREATE or ALTER any existing ROLE to be only enabled after 2-Step Authentication is completed (check "Usage Example" section for other examples).

P.S.: Ensure your system clock is synchronized with UTC and in the correct timezone.

4. Created Objects

The OraTOtP tool will create 1 new schema (which name you can define during installation) to hold all the packages and tables that will have the Time-based One-time Password configuration. This user will be locked and expired and is not intended to be used by anyone.

It consists on:

  • 1 New Schema with:
    • 3 Packages and their Bodys
    • 1 Procedure
    • 1 Trigger
    • 3 Tables and their Constraints and Indexes
  • 2 Public Synonyms (to avoid schema name typing)
  • 1 Context (to control 2-Factor authentication)

If you have Enterprise Edition DB, it will also create 1 function and 4 VPD policies to protect the schema tables.

If you have Database Vault Option, it will also create a realm to protect all the schema objects.

There are only 3 objects that need to be known:

 

  1. Package TWOFACTOR (used to do all tasks related with the 2-Factor. Granted to PUBLIC).
  2. Package TWOFACTOR_ADMIN (used to do all tasks admin tasks related with the 2-Factor. Must be granted to DBAs only).
  3. Procedure ENABLE_ROLE (used to enable any 2-Factor protected role. Granted to PUBLIC).

Those 3 objects are more detailed on "Documentation" section.

5. Installation

Download ZIP file (check "Download" section for more information) and extract all the files.

Open SQL*Plus and run INSTALL.sql.

Example 1:

  • Install for a local DB.
[oracle@mydbserver ~]$ sqlplus /nolog

SQL*Plus: Release 12.1.0.2.0 Production on Tue Oct 18 13:54:08 2016

Copyright (c) 1982, 2014, Oracle.  All rights reserved.

SQL> @INSTALL
Schema Name for 2-Factor [TOTP]: TOTP
String to connect as SYS [/ as sysdba]: / as sysdba
Connected.
DB Vault Users script skipped - Database Vault not enabled.
Connected.
User created.
Connected.
User privs granted.
Connected.
Objects created.
Policies created.
Connected.
DB Vault Realms script skipped - Database Vault not enabled.
=> SCRIPT EXECUTED SUCCESSFULLY! <=

Example 2:

  • Install for a remote database using TNS Names.
  • Here the DB Vault is enabled on the Database. In that case the script requests extra information.
[oracle@mydbserver ~]$ sqlplus /nolog

SQL*Plus: Release 12.1.0.2.0 Production on Tue Oct 18 11:20:13 2016

Copyright (c) 1982, 2014, Oracle.  All rights reserved.

SQL> @INSTALL
Schema Name for 2-Factor [TOTP]:
String to connect as SYS [/ as sysdba]: sys/Oracle.123@orcl as sysdba
Connected.
Oracle Database Vault Detected.
String to connect as DV Acct Mgr [/ as sysdba]: dvacctmgr/Oracle.123@orcl
String to connect as DV Owner [/ as sysdba]: dvowner/Oracle.123@orcl
String to connect as DBA [/ as sysdba]: system/Oracle.123@orcl
Connected.
User created.
Connected.
User privs granted.
Connected.
Objects created.
Policies created.
Connected.
Realm created.
=> SCRIPT EXECUTED SUCCESSFULLY! <=

Example 3:

  • Install for a remote DB using EZ Connect.
  • Setting the Schema Name as GAUTH instead of the default TOTP.
[oracle@mydbserver ~]$ sqlplus /nolog

SQL*Plus: Release 12.1.0.2.0 Production on Tue Oct 18 11:20:13 2016

Copyright (c) 1982, 2014, Oracle.  All rights reserved.

SQL> @INSTALL
Schema Name for 2-Factor [TOTP]: GAUTH
String to connect as SYS [/ as sysdba]: sys/Oracle.123@10.1.1.5/orcl as sysdba
Connected.
DB Vault Users script skipped - Database Vault not enabled.
Connected.
User created.
Connected.
User privs granted.
Connected.
Objects created.
Policies created.
Connected.
DB Vault Realms script skipped - Database Vault not enabled.
=> SCRIPT EXECUTED SUCCESSFULLY! <=

6. Documentation

TWOFACTOR:

This package must be granted to every DB user and is responsible for allowing the user to setup and authenticate for the 2-Fator Auth. Only after that he will be able to ENABLE any role protected with 2-Factor.

SETUP (PPASS IN VARCHAR2 DEFAULT NULL);
Will setup the current logged in user and generate an URL with a QR Code. This is the first step that must be done by anyone. Scan the generated Code with your mobile app. Before running, don't forget to enable SERVEROUTPUT.

Parameter:

PPASS - Optionally you can add a password to make the code seed irreversible by anyone. You can define any password up to 30 characters. It has nothing to do with your user account password, this one is used to encrypt your code generation seed to protect it.

VALIDATE (PCODE IN VARCHAR2, PPASS IN VARCHAR2 DEFAULT NULL);
After the user is SETUP, you must validate it providing a code that is generated by your app. Validation proves that you have setup the mobile app correctly and the code being generated is valid. Only after user is validated that it can authenticate and enable roles that are protected with 2-Factor Authentication.

Parameter:

PCODE - Give the code generated by the mobile app.

PPASS - If you have done the setup with a password, type it here to decode the seed.

AUTHENTICATE (PCODE IN VARCHAR2, PPASS IN VARCHAR2 DEFAULT NULL);
Now that user is SETUP and the code generator is VALIDATED, after every new login you need to authenticate it to be able to enable and activate the role having your privileges.

Parameter:

PCODE - Give the code generated by the mobile app.

PPASS - If you have done the setup with a password, type it here to decode the seed.

DECONFIG (PCODE IN VARCHAR2 DEFAULT NULL, PPASS IN VARCHAR2 DEFAULT NULL);
Will undo and clean any user configuration. Useful if your changing your mobile app to another phone or you want to rekey your seed. You need to provide a CODE if the user is already validated. If you lost your code generation app and cannot DECONFIG, ask support for the admin can help.

Parameter:

PCODE - Give the code generated by the mobile app if the user is already validated.

PPASS - If you have done the setup with a password, type it here to decode the seed.

REMEMBER (PCODE IN VARCHAR2, PPASS IN VARCHAR2 DEFAULT NULL);
This procedure will remember the machine, application and connection credentials your are coming from for 7 days. This location will be configured as trusted. During that time, when you establish a new connection it will be automatically AUTHENTICATE. All you need is to enable the role.

Parameter:

PCODE - Give the code generated by the mobile app.

PPASS - If you have done the setup with a password, type it here to decode the seed.

FORGET;
This procedure will clean all the remembered connections sources linked to your user.

TWOFACTOR_ADMIN:

This package is very similar to TWOFACTOR package unless that you can also manage other users with it. Thus it must be granted only to 2-Factor Admins (or DBA's). Basically all the procedures are the same adding a "PUSER" parameter.

SETUP (PUSER IN VARCHAR2, PPASS IN VARCHAR2 DEFAULT NULL, PGAP IN NUMBER DEFAULT NULL);
Same as TWOFACTOR.SETUP, unless that it will setup the user specified by PUSER parameter (not the session user).

Parameter:

PUSER - Username affected by the procedure.

PPASS - Optionally you can add a password to make your code seed irreversible by any DB admin.

PGAP - Time gap in seconds to also accept codes based on time difference errors. One new code is generated every 30 seconds, however, to avoid problems, by default (if null input) we add a gap of 480 seconds (8 minutes) = 4 minutes up and down. That means that if your mobile clock is at 12h00 and server clock is at 12h04, your generated code will still be accessible. The accepted limit is 1200 seconds (20 minutes) = 10 minutes up and down.

VALIDATE (PUSER IN VARCHAR2, PCODE IN VARCHAR2, PPASS IN VARCHAR2 DEFAULT NULL);
Same as TWOFACTOR.VALIDATE, unless that it will validate the user specified by PUSER parameter (not the session user).

Parameter:

PUSER - Username affected by the procedure.

PCODE - Give the code generated by user mobile app.

PPASS - If user have done the setup with a password, type it here to decode the seed.

AUTHENTICATE (PCODE IN VARCHAR2, PPASS IN VARCHAR2 DEFAULT NULL);
Same as TWOFACTOR.AUTHENTICATE. You cannot authenticate for another user.

Parameter:

PCODE - Give the code generated by user mobile app.

PPASS - If you have done the setup with a password, type it here to decode the seed.

DECONFIG (PUSER IN VARCHAR2, PCODE IN VARCHAR2 DEFAULT NULL, PPASS IN VARCHAR2 DEFAULT NULL, PISADMIN IN BOOLEAN DEFAULT TRUE);
Same as TWOFACTOR.DECONFIG, unless that it will deconfigure the user specified by PUSER parameter (not the session user).

Parameter:

PUSER - Username affected by the procedure.

PCODE - Give the code generated by user mobile app. Ignored if PISADMIN is true (default behavior).

PPASS - If user have done the setup with a password, type it here to decode the seed.

PISADMIN - When this parameter is true (default behavior), you don't need to give a code to deconfigure already validated users.

REMEMBER (PCODE IN VARCHAR2, PPASS IN VARCHAR2 DEFAULT NULL, PINT IN INTERVAL DAY TO SECOND DEFAULT NULL);
Same as TWOFACTOR.REMEMBER. You cannot remember login specs for another user.

Parameter:

PCODE - Give the code generated by user mobile app.

PPASS - If user have done the setup with a password, type it here to decode the seed.

PINT - Interval of days to remember the credentials. If not specified, it defaults to 7 days.

FORGET (PUSER IN VARCHAR2);
Same as TWOFACTOR.FORGET, unless that it will forget the login specs of the user specified by PUSER parameter (not the session user).

Parameter:

PUSER - Username affected by the procedure.

ENABLE_ROLE:

This procedure is used to enable a protected role.

ENABLE_ROLE (ROLE_NAME IN VARCHAR2);
Will add the protected role named passed as parameter to your list of enabled roles, by running "SET ROLE". You must be authenticated in 2-Factor to be able to execute it.

Parameter:

ROLE_NAME - Protected role name that you want to enable in your session.

TABLES and COLUMNS:

Check tables and columns comments.

7. Usage Example

First step is to create a ROLE that you want to be protected by 2-Factor authenticaion:

SQL> CREATE ROLE APPOBJACCESS IDENTIFIED USING TOTP.ENABLE_ROLE;

Role created.

SQL>

P.S: You can optionally alter an existing roles to be only enabled after user is authenticated by 2-Factor.

Now, let's create a new user to show how it works:

SQL> CREATE USER USER1 IDENTIFIED BY "User1";

User created.

SQL> GRANT CREATE SESSION TO USER1;

Grant succeeded.

SQL> GRANT APPOBJACCESS TO USER1;

Grant succeeded.

SQL>

Role is created and granted to USER1, let's try to connect and enable the role:

SQL> conn User1/User1
Connected.
SQL> select * from session_roles;

no rows selected

SQL> set role APPOBJACCESS;
set role APPOBJACCESS
*
ERROR at line 1:
ORA-01924: role 'APPOBJACCESS' not granted or does not exist

SQL> exec enable_role('APPOBJACCESS');
BEGIN enable_role('APPOBJACCESS'); END;
*
ERROR at line 1:
ORA-20000: User not authenticated in 2Factor.
ORA-06512: at "TOTP.ENABLE_ROLE", line 14
ORA-06512: at line 1

SQL>

As you can see, role cannot be enabled via set command. The right way is to use the enable_role procedure, however, the user must authenticate first. As this user is not even yet configured, let's set it up:

SQL> set serveroutput on
SQL> set lines 1000
SQL> exec twofactor.setup;
https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=%6F%74%70%61%75%74%68%3A%2F%2F%74%6F%74%70%2F%55%53%45%52%31%40%4F%52%43%4C%3F%73%65%63%72%65%74%3D%56%53%4D%34%50%52%35%41%4B%56%44%52%47%59%55%35%26%69%73%73%75%65%72%3D%44%42%20%53%65%72%76%65%72%20%2D%20%6F%72%63%6C%2E%75%73%2E%6F%72%61%63%6C%65%2E%63%6F%6D

PL/SQL procedure successfully completed.

SQL>

P.S: If you forget to enable serveroutput before running the SETUP procedure, just run the DECONFIG, enable it and then rerun setup.

Open the returned link address in a browser and scan the QR Code using "Google Authenticator" (or any other TOTP app that you prefer):

After your app is configured, it will start generating the codes as below:
You can now validate:

SQL> exec twofactor.validate(682286);

PL/SQL procedure successfully completed.

SQL>

With 2-Factor validated, from now on all you need to do after a creating a new connection is authenticate and enable the role:

SQL> select * from session_roles;

no rows selected

SQL> exec twofactor.authenticate(390564);

PL/SQL procedure successfully completed.

SQL> exec enable_role('APPOBJACCESS');

PL/SQL procedure successfully completed.

SQL> select * from session_roles;

ROLE
------------------------------
APPOBJACCESS

SQL>

Optionally, you can ask the 2-Factor authentication system to trust in your location for the next 7 days, so you won't need to re-authenticate after every new login coming from the same machine, terminal, IP, program and OS user:

SQL> conn User1/User1
Connected.
SQL> exec enable_role('APPOBJACCESS');
BEGIN enable_role('APPOBJACCESS'); END;
*
ERROR at line 1:
ORA-20000: User not authenticated in 2Factor.
ORA-06512: at "TOTP.ENABLE_ROLE", line 14
ORA-06512: at line 1

SQL> exec twofactor.authenticate(388648);

PL/SQL procedure successfully completed.

SQL> exec enable_role('APPOBJACCESS');

PL/SQL procedure successfully completed.

SQL> exec twofactor.remember(471508);

PL/SQL procedure successfully completed.

SQL> conn User1/User1
Connected.
SQL> exec enable_role('APPOBJACCESS');

PL/SQL procedure successfully completed.

SQL>

8. Download

https://github.com/dbarj/OraTOtP/archive/master.zip

---------------------------
Checksum information
---------------------------
Name: OraTOtP-1.00.zip
Size: 30248 bytes (0 MB)
CRC32: 9532060D
CRC64: F95F37109D5196B1
SHA256: 2339020753EE758969E2E500D5A4A29DD3D1FDFD9B14844EFD272567D4F54A4F
SHA1: C458801D32AC2B192ABD7AF2FC74099B08E5C269
BLAKE2sp: DF7E1399F2912244A02DEC6EFECEC617277321E0FD35AAB66AD7625F8DB3EA7F

Have you enjoyed? Please leave a comment or give a 👍!

13 comments

Skip to comment form

  1. Man, very well done! Great approach!
    I will test it soon.

    Best wishes,

    Franky

    • trim on November 15, 2016 at 08:59
    • Reply

    thanks a lot for great solution!

    • Adric Norris on February 28, 2017 at 18:43
    • Reply

    This looks very nice! I definitely need to play around with it a bit. 🙂

    • Md. Rasel Parvej on January 24, 2018 at 05:12
    • Reply

    exec twofactor.validate(571486);
    BEGIN twofactor.validate(571486); END;

    *
    ERROR at line 1:
    ORA-20000: Code not valid.
    ORA-06512: at "TOTP.TWOFACTOR_ADMIN", line 91
    ORA-06512: at "TOTP.TWOFACTOR", line 36
    ORA-06512: at line 1

    1. Hi Rasel,
      Check if your database server time and your mobile device time are correct. By default OraTOTP has a 4 minutes security margin to accept codes due to clock errors. If they are on different timezones, you need to ensure that they both point to same UTC time.
      Let me know if you have any questions.

    • Rim on November 28, 2018 at 10:22
    • Reply

    Hello Sir

    i want to remove remember two factor.
    exec twofactor.remember(681834);

    could you share me how to remove?

    • Isaac on September 20, 2019 at 16:15
    • Reply

    Thanks Rodrigo for this, great blog with clear steps to follow. One question, would you require internet access on the database server to make this work or it is possible to implement without internet access? And also for various other users?

    Thanks
    Isaac

    1. Hi Issac, no internet access is needed by the server. It's all offline.
      When you enable 2-factor for your account, you will be given a link that converts a text to a QR code. The only required internet connection will be when you copy and paste this link somewhere to generate it (can be your phone or your own compute).
      Regards,
      RJ

    • Pierre on October 21, 2019 at 09:21
    • Reply

    Hey, that's great work, I wonder How can I program my own Qcode? Any tips for this.

    Thanks P.

    • david on January 6, 2020 at 16:49
    • Reply

    Hi,
    I have an iphone, and I am getting:
    invalid activation barcode. Any idea?
    I'm using google authenticator, I tried also the microsoft and get the same error.
    Thanks David

    1. Hi David, I don't know what this can be.. can you share a test or fake generated code so I can check it?

    • David on January 13, 2020 at 15:09
    • Reply

    It's working now, I removed the Blank in the Server string.
    It's working fine, thanks a lot !!!

  2. A new alternative is to use a reprogrammable hardware token (they can be used anywhere where google authenticator can be used). The advantage is you are no longer dependant upon having your mobile device with you (both are battery powered, but token batteries typically last 5 years or so).

Leave a Reply

Your email address will not be published.