Protección de procedimientos almacenados en MySQL
Bienvenidos al nuevo blog de Tarlogic, donde intentaremos ir desasrrollando artículos técnicos enfocados a la seguridad de aplicaciones web o al despliegue de aplicaciones y técnicas de pentesting.
En este primer artículo se hablará de la protección de ataques de inyección sql en los procedimientos almacenados de una base de datos MySQL.
En ocasiones, parte de la operativa de acceso a datos de las aplicaciones se realiza mediante el uso de procedimientos almacenados de MySQL.
La necesidad del uso de procedimientos almacenados en MySQL es muy variada y puede depender en gran medida del tipo de aplicación que se esta desarrollando pero, la mayoría de la gente coincide que tres de las razones principales para su uso son:
- Integridad de la información: Centralizando el acceso a cierta información a través de un único mecanismo.
- Seguridad, por la posibilidad que ofrece un procedimiento almacenado de ejecutar acciones con privilegios diferentes.
- Rendimiento, dado que es el propio motor el que se encarga de realizar las transacciones.
La principal forma de garantizar la seguridad del código, ejecutado dentro de un procedimiento almacenado, es usando una sentencia preparadaen la que los parámetros del procedimiento son validados correctamente, de forma que se eviten ataques de inyección SQL. A continuación se muestra un ejemplo de una consulta preparada a la que se envían dos parámetros:
mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> SET @a = 3;
mysql> SET @b = 4;
mysql> EXECUTE stmt1 USING @a, @b;
Cuando el código SQL ejecutado dentro de un procedimiento es código SQL dinámico, generado en base a parámetros enviados por el usuario o, en determinadas sentencias SQL, que no soportan el uso de sentencias preparadas, puede ser complejo garantizar la seguridad en la ejecución del código SQL.
Se ha indicado previamente que un procedimiento almacenado se puede ejecutar con privilegios superiores. Por ello, el riesgo para la seguridad de la base de datos que supone ejecutar procedimiento almacenado mal programado es elevado. Un procedimiento almacenado de una bbdd es un foco potencial de ataques de un hacker.
El lector estará pensando seguramente que para realizar la validación de los datos, es el propio motor de la aplicación web el que debe filtrarlos. Esto es correcto solo en parte.
La aplicación debe ser capaz de proteger de entradas malformadas a la base de datos pero, si un usuario es capaz de conectarse directamente a la base de datos, por ejemplo desde uno de nuestros servidores web comprometidos, se esta facilitando a un intruso la posibilidad de ejecutar comandos arbitrarios con los privilegios de nuestro procedimiento almacenado.
Este ataque no sea trivial, pero es una vía muy interesante para comprometer un sistema.
La alternativa a este dilema es sencilla de explicar. Debe ser el procedimiento almacenado el que verifique el tipo de dato que espera y el que elimine de los parámetros de entrada aquellos caracteres de control de SQL que puedan modificar el flujo lógico de la consulta.
Por desgracia, MySQL no ofrece ninguna llamada nativa para validar datos de entrada como es el caso de mysql_escape_string de PHP. Para solucionar esto, se puede desarrollar un procedimiento de validación propio.
-- -----------------------------------------------------
— function my_mysql_escape_string
— —————————————————–
DROP FUNCTION IF EXISTS `my_mysql_escape_string`;
SHOW WARNINGS;DELIMITER $$
CREATE FUNCTION my_mysql_escape_string( cadena VARCHAR(255) ) RETURNS VARCHAR(255)
BEGIN
RETURN REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(cadena,’\\’,’\\\\’),’\0′,’\\0′),’\n’,’\\n’),’\r’,’\\r’),’\x1a’,’\\z’),'”‘,’\\”‘),”‘”,”\\'”);
RETURN @cadena;
END
A partir de este momento, se pueden empezar a enviar los parámetros de entrada sin filtrar ya que el propio procedimiento almacenado se encargada de evitar ataques de inyección SQL.
DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `protected_against_sql_injection`(IN UserName VARCHAR(50))
SET @_UserName = my_mysql_escape_string(UserName);
-- do stuff
-- do more stuff
END
$$
DELIMITER ;
Con esta sencilla función de MySQL podemos proteger procedimientos almacenados que generan código SQL dinámico de una forma rápida y segura.
Un saludo y hasta la próxima.
Descubre nuestro trabajo y nuestros servicios de ciberseguridad en www.tarlogic.com/es/
En TarlogicTeo y en TarlogicMadrid.