jueves, 13 de agosto de 2009

Cómo ocultar el código de PL/SQL

Puede el código PL/SQL ser escondido y protegido de miradas ajenas, cuando lo implantamos en alguna base de datos externa?

La respuesta a esta inquietud es SI, gracias a un ejecutable y un paquete disponible que nos permite compilar un procedimiento almacenado y hacer que el fuente quede confuso para quien intenta leerlo.
Oracle se refiere a este método como ofuscamiento "obfuscation" (el término ofuscar en el diccionario tiene el significado de "oscurecer, encubrir").

Es curioso como todavía hay empresas que desarrollan software de altísimo valor corporativo y lo implantan expuestamente en bases de datos de usuarios finales que en muchos casos tiene acceso la propia competencia. No todos en la industria son mal intencionados, pero es mejor prevenir que lamentar perder margen de ventaja.

Qué encriptar

Todo lo que sea código almacenado: procedimientos, funciones, paquetes y tipos. La excepción son los triggers, el método no los soporta, sin embargo una solución es pasar la lógica a un procedure encriptado y llamarlo desde el trigger.

Una recomendación: usemos un criterio, no seamos paranoicos.
Muy a menudo, parte de nuestro código tiene que ser compartido con otros proveedores, necesitamos disponibilizar ciertos objetos para que otros puedan construir sus propios programas a partir de ellos. No necesitamos ofuscar todos los paquetes de nuestra base de datos, solamente aquellos que tengan lógica de negocio sensible de la compañia, como algoritmos, paquetes financieros, lógica de procesamiento, mantenimiento de cuentas, paquetes de seguridad, etc.

Oracle no recomienda usar este método para encriptar contraseñas, ya que si abrimos el archivo generado, podremos ver identificadores y reconocer algunas palabras que están presentes en el código original.

Antes de comenzar

Es importante tener en cuenta que estaremos escondiendo el código de miradas ajenas y hasta de la nuestra, ya que una vez que el código está encriptado en la base de datos, no hay forma ni usuario que pueda recuperarlo. Para realizar modificaciones, hay que hacerlas sobre la versión de texto original. La recomendación es usar un manejador de versiones como repositorio de código, y luego adoptar la práctica de encriptar antes de recompilar.

Cómo encriptar

Existe un ejecutable en $ORACLE_HOME/bin que se llama wrap.
Llamándolo desde la consola, y pasándole el nombre de un script en el parámetro iname, nos retorna un archivo de texto .plb con código interno, el cual podremos compilar en SQL*plus para crear el objeto almacenado "ofuscado".

Ejemplo 1

Vamos a encriptar un procedimiento. Para ello ya tenemos el código del mismo en un archivo ob_proc.sql, copiado en el servidor de la base de datos. Todo lo que tenemos que hacer es entrar en la consola y ejecutar:

wrap edebug=wrap_new_sql iname=ob_proc.sql

PL/SQL Wrapper: Release 9.2.0.8.0- Production on Thu Aug 13 11:38:30 2009 Copyright (c) Oracle Corporation 1993, 2001. All Rights Reserved.

Processing ob_proc.sql to ob_proc.plb


Nota: El flag edebug=wrap_new_sql es necesario para poder soportar el nuevo compilador de sql y corregir un bug existente con algunas sintaxis de sql avanzado.

La salida, es el archivo encriptado ob_proc.plb, el cual ahora podemos compilar en SQL*plus.

SQL> @ob_proc.plb

Procedure created.

Esta pronto. El código del procedure en la base de datos no es más legible, ya sea usando cualquier programa de desarrollo, paquete Oracle o vista del diccionario. Sin embargo es perfectamente ejecutable como cualquier otro procedimiento.

Ejemplo 2

Ahora encriptaremos un paquete. Se realiza en forma similar, recordando que el paquete se compone por especificación y opcionalmente un cuerpo. Si bien podemos encriptar ambos, se recomienda en la mayoria de los casos encriptar únicamente el cuerpo. Después de todo, es donde reside la lógica que queremos proteger. La especificación es útil muchas veces para consultar la firma de las funciones que están siendo expuestas, y es amable disponibilizarlas para el uso común.

Teniendo el cuerpo de nuestro paquete preparado en el archivo ob_pack_body.sql, ejecutamos:

wrap edebug=wrap_new_sql iname=ob_pack_body.sql

PL/SQL Wrapper: Release 9.2.0.8.0- Production on Thu Aug 13 11:38:30 2009 Copyright (c) Oracle Corporation 1993, 2001. All Rights Reserved.

Processing ob_pack_
body.sql to ob_pack_body.plb

Si nuestro paquete ya estaba compilado en la base de datos, recordemos que únicamente necesitamos recompilar el cuerpo. De lo contrario, tendremos que compilar la especificación primero.

SQL> @ob_pack_body.plb

Package body created.

El código de especificación del paquete, que ya estaba compilado, continúa siendo visible, mientras que el body ahora fue ocultado y no está más disponible a la vista de todos.

Ver también:
Cómo extraer código en archivos separados