Si los usuarios pueden insertar, actualizar, o borrar registros de las tablas desde afuera de nuestras aplicaciones (Contabilidad, Producción, Sueldos, Ventas, etc.) eso solamente puede significar problemas, nada bueno obtendremos de sus acciones.

Por ejemplo, un empleado se enteró de cual es el password del usuario SYSDBA y como ese empleado conoce suficiente de Informática entonces se conecta a la Base de Datos como SYSDBA y estando allí … hace lo que se le ocurre.

Algunos ejemplos de lo que podría hacer:

  1. Se aumenta su propio sueldo, digamos en un 8%
  2. Se pone de acuerdo con un cliente de la empresa para marcar como cobrada una Factura que aún no ha sido cobrada
  3. Un alumno se aplazó en una materia, pero la marca como aprobada
  4. Modifica el precio de venta de un producto para que el vendedor cobre una comisión mayor por esa venta

Inclusive si es inteligente, podría aumentar su sueldo y también el de otros empleados más para que sea más difícil deducir que fue él quien lo alteró. Si un solo empleado recibió un aumento fraudulento de sueldo cuando se detecte todas las miradas se dirigirán hacia él; pero si son 30 los empleados que recibieron el aumento fraudulento del sueldo será más difícil encontrar al culpable. Si es lo suficientemente astuto inclusive pondrá en la lista de beneficiarios a aquellas personas con las cuales no se lleva bien: si Juan es el empleado deshonesto y todos saben que él y Raúl son enemigos, si Raúl también recibió el aumento (e inclusive un aumento mayor) será más difícil creer que el culpable es Juan.

Y entonces ¿por qué ocurrió ese aumento fraudulento? para los propietarios de la Empresa la respuesta es fácil … porque la aplicación de Sueldos falló, y por lo tanto el programador es el culpable. Y claro, el pobre programador puede pasarse horas y horas buscando errores en su código fuente y jamás los encontrará, porque el problema no está en su programa sino en la modificación de las tablas desde afuera de su programa.

¿Cómo se puede detectar si una fila se insertó o modificó desde afuera de nuestras aplicaciones?

Una técnica es agregándole a cada tabla una columna para “checksum”. Un checksum es un número que se usa para controlar que los datos que existen en las demás columnas fueron puestos de forma autorizada.

DETECTAR1

(si haces clic en la imagen la verás más grande)

En este ejemplo a la tabla de BANCOS se le agregó una columna llamada BAN_CHECKS donde se guardará el checksum de la fila.

Para generar el checksum un método es el siguiente:

  • Convertir el valor de cada columna a carácter
  • Concatenar todas esas columnas
  • Concatenarle un testigo
  • Grabar el hash

Ejemplo en Visual FoxPro:

Si conoces el lenguaje Visual FoxPro aquí puedes ver una posible implementación:

WITH ThisForm
   M.BAN_CODSUC = .Text1.Value
   M.BAN_IDENTI = .Text2.Value
   M.BAN_NOMBRE = .Text3.Value
   M.BAN_CHECKS = Str(M.BAN_CODSUC, 2) + Str(M.BAN_IDENTI, 3) + M.BAN_NOMBRE + "ASU-PAR-123456"
ENDWITH

lcComando = "EXECUTE PROCEDURE Grabar_Banco(?M.BAN_CODSUC, ?M.BAN_IDENTI, ?M.BAN_NOMBRE, ?M.BAN_CHECKS)"

=SQL_Exec(gnHandle, lcComando)

Y este es el stored procedure Grabar_Banco:

SET TERM ^ ;

CREATE PROCEDURE GRABAR_BANCO(
   CodSuc TYPE OF COLUMN BANCOS.BAN_CODSUC,
   Identi TYPE OF COLUMN BANCOS.BAN_IDENTI,
   Nombre TYPE OF COLUMN BANCOS.BAN_NOMBRE,
   CheckS TYPE OF COLUMN BANCOS.BAN_CHECKS)
AS
BEGIN

   UPDATE OR INSERT INTO BANCOS
            (BAN_CODSUC, BAN_IDENTI, BAN_NOMBRE, BAN_CHECKS)
     VALUES (:CodSuc   , :Identi   , :Nombre   , Hash(:CheckS)) ;

END^

SET TERM ; ^

¿Qué es un testigo?

Son los caracteres adicionales que se le agregan a un string para que los intrusos no obtengan el mismo resultado del hash que obtenemos nosotros. En el ejemplo el testigo es ASU-PAR-123456

Aunque los intrusos obtengan y graben un hash en la columna BAN_CHECKS jamás obtendrán el mismo resultado porque ellos no le están agregando el testigo al string.

Por ejemplo, ellos escriben:

INSERT INTO BANCOS VALUES(0, 0, ‘BANCO ITAÚ’, HASH(‘0 0 BANCO ITAÚ’))

Pero nosotros escribimos:

INSERT INTO BANCOS VALUES(0, 0, ‘BANCO ITAÚ’, HASH(‘0 0 BANCO ITAÚ ASU-PAR-123456’))

Y como los strings que son argumentos de la función HASH() son distintos también lo serán los valores devueltos por dicha función. Si ellos no saben que le agregamos un testigo al string (o lo saben, pero no saben cual es ese testigo) jamás obtendrán el mismo resultado de la función HASH()

Detectando una inserción o modificación no autorizada:

Al escribir: SELECT * FROM BANCOS esto es lo que obtenemos:

DETECTAR2

(si haces clic en la imagen la verás más grande)

¿Cómo podemos averiguar si todas las columnas tienen valores legítimos o alguna es fraudulenta?

Escribiendo el comando:

SELECT
   HASH(CAST(BAN_CODSUC AS CHAR(2)) || CAST(BAN_IDENTI AS CHAR(3)) || BAN_NOMBRE || 'ASU-PAR-123456') AS MiCheck,
   BAN_CHECKS
FROM
   BANCOS

Y esto es lo que obtenemos:

DETECTAR3

(si haces clic en la imagen la verás más grande)

 Si te fijas con atención verás que en la última fila los números no coinciden. ¿Por qué no coinciden? Porque fue ingresada de forma fraudulenta, o sea desde afuera de nuestra aplicación.

Si solamente quieres ver las filas fraudulentas podrías escribir:

SELECT
   BAN_CODSUC,
   BAN_IDENTI,
   BAN_NOMBRE
FROM
   BANCOS
WHERE
   HASH(CAST(BAN_CODSUC AS CHAR(2)) || CAST(BAN_IDENTI AS CHAR(3)) || BAN_NOMBRE || 'ASU-PAR-123456') <> BAN_CHECKS

Y en ese caso obtendrías esto:

DETECTAR4

(si haces clic en la imagen la verás más grande)

 Conclusión:

Si usas la función HASH() en una columna de checksum y a la función HASH() además del string con los datos le envías un testigo podrás demostrar que el valor que tiene una columna fue puesto desde afuera de tu aplicación. Y por lo tanto, tu programa no es el culpable de cualquier cosa mala que haya pasado.

Para tu mayor protección podrías firmar un contrato con tu cliente donde especificas claramente que te desligas de toda  responsabilidad si alguna fila fue insertada o modificada desde afuera de tu aplicación.

Artículos relacionados:

La función HASH()

El índice del blog Firebird21