Uno de los temas que más buscamos los desarrolladores en conocer cómo mejorar la seguridad en nuestras aplicaciones desarrolladas en Application Express. Así como el administrador de la Instancia o el Espacio de Trabajo debe velar por la seguridad de la Base de Datos, el desarrollador debe velar por la seguridad de las aplicaciones que desarrolla.
Cuando creamos nuestras aplicaciones en Oracle Apex todo el proceso de autenticación lo maneja internamente el motor de Apex permitiéndonos ingresar a nuestra aplicación por el solo hecho de ser un usuario registrado del espacio de trabajo al cual pertenece nuestra aplicación.
Lógicamente esto acelera en gran medida el desarrollo de la aplicación ya que no necesitamos crear y manejar la autenticación de los usuarios, pero sí necesitamos almacenar la información de los usuarios que acceden a nuestra aplicación en una tabla en nuestro esquema y controlar que niveles de acceso tienen en la aplicación, necesitamos aprender a crear una autenticación personalizada.
¿En qué casos vamos a utilizar un esquema personalizado de autenticación?
- Cuando la autenticación de la base de datos o de otros métodos no son adecuados.
- Cuando queremos desarrollar nuestro propio formulario de acceso y métodos asociados.
- Cuando deseamos controlar los aspectos de seguridad de la administración de sesiones.
- Cuando queremos auditar las actividades a nivel de usuario o sesión.
- Cuando queremos hacer cumplir límites de actividad de sesión o de caducidad.
- Cuando deseamos programar una redirección condicional antes del procesamiento de página.
- Cuando queremos integrar nuestra aplicación con aplicaciones que no son de Oracle Application Express utilizando un framework común para la gestión de sesiones.
- Cuando nuestra aplicación consta de varias aplicaciones que funcionan perfectamente integradas (por ejemplo, más de un ID de aplicación).
Para este ejemplo, vamos a crear una aplicación de tipo Escritorio dentro de nuestro espacio de trabajo.
Crear Aplicación Demo
Posteriormente vamos a crear una tabla que contendrá los datos de los usuarios.
Crear Tabla de Usuarios
Para ello ingresamos al Taller SQL y ejecutamos las siguientes sentencias una a una:
CREATE table "MY_USERS" ( "USER_ID" NUMBER(8,0) NOT NULL, "USER_NAME" VARCHAR2(100) NOT NULL, "USER_PASSWORD" VARCHAR2(4000) NOT NULL, constraint "MY_USERS_PK" primary key ("USER_ID") ) / CREATE sequence "MY_USERS_SEQ" / CREATE trigger "BI_MY_USERS" before insert on "MY_USERS" for each row begin if :NEW."USER_ID" is null then select "MY_USERS_SEQ".nextval into :NEW."USER_ID" from sys.dual; end if; end; /
Crear Funciones en la Base de Datos
Para poder disponer de nuestro esquema de autenticación personalizado necesitamos para este ejemplo tener dos funciones en la base de datos, una de las funciones MY_AUTH se encargará de verificar que el usuario está en la base de datos según las credenciales almacenadas en la tabla MY_USERS y la otra función MY_HASH se encargará de encriptar la contraseña utilizando el algoritmo hash.
La función MY_AUTH recibe el nombre de usuario y contraseña como parámetros desde el formulario de inicio de sesión y compara esta información con los valores almacenados en la tabla MY_USERS después de aplicar la función MY_HASH. Si la información proporcionada coincide con los valores de la tabla, el usuario es autenticado y se le permite acceder a la aplicación.
MY_AUTH FUNCTION
create or replace function my_auth (p_username in VARCHAR2, p_password in VARCHAR2) return BOOLEAN is l_password varchar2(4000); l_stored_password varchar2(4000); l_count number; begin -- Primero, verificar que el usuario existe en la tabla select count(*) into l_count from my_users where user_name = p_username; if l_count > 0 then -- Recuperar la contraseña hash almacenada select user_password into l_stored_password from my_users where user_name = p_username; -- Aplicar la función hash al password l_password := my_hash(p_username, p_password); -- Comparar y ver si son los mismos y retornar VERDADERO o FALSO if l_password = l_stored_password then return true; else return false; end if; else -- El nombre de usuario provisto no se encuentra en la tabla MY_USERS return false; end if; end;
MY_HASH FUNCTION
create or replace function my_hash (p_username in varchar2, p_password in varchar2) return varchar2 is l_password varchar2(4000); l_salt varchar2(4000) := 'ISYmHMtSrjFmT2nEZUvEU5LA3jrV3i'; begin l_password := utl_raw.cast_to_raw(dbms_obfuscation_toolkit.md5(input_string => p_password || substr(l_salt,10,13) || p_username || substr(l_salt, 4,10))); return l_password; end;
Creamos los archivos my_hash.sql y my_auth.sql y lo guardamos en nuestro Escritorio.
Encriptar la función MY_HASH
Si nosotros subimos este script a nuestra base de datos, cualquiera que tenga acceso a los objetos de la base de datos podrá ver de qué forma estamos realizando la encriptación de las contraseñas, por ello es muy importante antes de subir el script poder encriptarlo.
Para encriptar nuestra función haremos uso de la la utilidad Wrapper que es un ejecutable que se encuentra en la ruta $ORACLE_HOME/bin y que permite ofuscar un archivo sql haciendo uso de su parámetro iname.
Hacemos una copia del script my_hash.sql dentro de la carpeta $ORACLE_HOME/bin que en mi caso es:
C:\oraclexe\app\oracle\product\11.2.0\server\bin
Luego abrimos una ventana de comandos CMD en Windows, nos dirigimos a la ruta donde se encuentra el archivo sql y luego ejecutamos el comando wrap iname= my_hash.sql y esperamos a que la ejecución del comando finalice.
Si abrimos el archivo my_hash.plb en un Notepad++ o cualquier editor de código, podremos ver la primer línea como create or replace function my_hash wrapped y luego el resto del archivo estará oculto.
Ahora que tenemos encriptada la función my_hash podemos subirla a nuestro esquema.
Lo podemos hacer desde el Taller de SQL o abrimos una ventana de comandos CMD y nos conectamos al SQLPlus y luego nos conectamos al usuario de nuestro esquema:
SQL> conn clartech/************ SQL> @c:\oraclexe\app\oracle\product\11.2.0\server\bin\my_hash.plb
El mensaje que aparecerá es que la funcion ha sido creada.
Si ingresamos al Explorador de Objetos y visualizamos la función podremos ver que está encriptada, de igual forma como lo vimos cuando la abrimos en el Notepad++.
Crear la función my_auth.sql.
Ingresamos al Taller de SQL:
- Seleccionamos Archivos de Comandos SQL
- Hacemos clic en el botón Cargar
- Hacemos clic en el botón Browse y seleccionamos el archivo my_auth.sql y hacemos clic en el botón cargar
- Ejecutamos el script my_auth.sql y esto creará la función dentro de la base de datos
Registrar Usuarios en la base de datos
Ejecutamos las siguientes sentencias en el Taller de SQL
Insert into MY_USERS (user_id, user_name, user_password) values (1, upper('Fernando'), my_hash(upper('Fernando'),'Secret1')); Insert into MY_USERS (user_id, user_name, user_password) values (2, upper('Marcelo'), my_hash(upper('Marcelo'),'Secret2'));
Si abrimos la tabla MY_USERS podemos ver que las claves están encriptadas.
Ya tenemos las funciones y la tabla usuarios para especificar nuestro propio esquema de autenticación.
Asignar nuestro propio esquema personalizado de autenticación
- Nos dirigimos a la página de Inicio de la Aplicación
- Hacemos clic en Componentes Compartidos
- En la sección Seguridad hacemos clic en el enlace Esquemas de Autenticación
- En este momento tenemos el esquema APEX – Actual en uso, vamos a cambiarle el nombre a Esquema Personalizado
- En tipo de Esquema seleccionamos Personalizado de la Lista de Selección
- En Nombre de la Función de Autenticación ingresamos: my_auth
- Hacemos clic en el botón Aplicar Cambios
Ejecutamos la aplicación e ingresamos las credenciales de nuestro usuario dentro del Espacio de Trabajo, al no estar en la tabla MY_USERS, se deniega el acceso a la aplicación.
Ahora ingresamos las credenciales del usuario que hemos creado en la tabla MY_USER, por ejemplo Fernando:
Conclusión
Como podemos ver, crear un esquema propio de autenticación es bastante sencillo en Application Express, lo importante es gestionar la seguridad de nuestras aplicaciones responsablemente.
Hasta pronto!