Os mostramos un método seguro para enviar los datos mediante URL usando POST o GET, tanto si se ve la URL directamente en el navegador como si se oculta. Este método consiste en calcular el hash en MD5 de los valores que pasamos mediante POST o GET y, posteriormente, no revertiremos el MD5, de hecho es irreversible, lo que haremos será calcularlo también en la parte de MySQL para las actualizaciones y eliminaciones de registros.

Método POST y GET de HTML poco seguro, envío de parámetros mediante URL

Cuando queremos usar URL con parámetros para transferir datos de un formulario a otro o de una página a otra o sobre la misma página, podemos hacerlo mediante GET, usando el típico:

…url?parametro=valor

Mediante $_GET[«parametro»] o bien (más seguro), mediante filter_input(INPUT_GET, «parametro»), podemos obtener el valor pasado por la URL. Pero en ambos casos el usuario podría interceptar dichos valores e incluso enviar URL con otros valores y ser peligroso.

Por ejemplo, si nuestra aplicación elimina un registro al usar la URL con GET:

…url?eliminar_cliente=33

Un usuario con mínimos conocimientos puede obtener estos valores, incluso si se pasan mediante POST, y generar una URL con la misma estructura y diferente ID, por ejemplo:

…url?eliminar_cliente=21

Provocando la eliminación del registro 21 de nuestra tabla de clientes.

Por lo tanto y sobre todo en caso de eliminaciones y actualizaciones en base de datos hay que aplicar varios mecanismos de seguridad para evitar acciones malintencionadas o los descuidos. Existen numerosas opciones para evitar en la medida de lo posible llegar a una situación de este tipo, a continuación os exponemos una de ellas.

Codificar las URL usando MD5 tanto en el GET como en la consulta a la base de datos con PHP

Explicamos un método para securizar los datos que enviamos por parámetro y obtenemos mediante GET en PHP. Usaremos para ello la función MD5 de PHP y también la función MD5 de MySQL. De esta forma no necesitaremos generar una clave «encriptada» y luego aplicar el algoritmo inverso para desencriptarla, lo que haremos será aplicar un algoritmo de encriptación no reversible, el HASH.

La mejor manera de entenderlo es explicarlo con un ejemplo, supongamos que tenemos una tabla donde mostramos los partes de trabajo, en la parte derecha de la tabla colocamos un botón «Eliminar» para cada registro, con su ID correspondiente. De forma que pulsando en él el usuario eliminar el registro correspondiente al botón. Sería algo así (usando el método sencillo pero NADA recomendable):

Este código estará dentro de un while (por ejemplo) que recorrerá todos los registros de la tabla que cumplan el SQL y mostrará en la tabla HTML una línea por cada registro, con su botón «Eliminar» correspondiente, que se diferencia por el campo «codigo» de la tabla correspondiente:

Mostrando algo así en el navegador:

Método para camuflar de forma segura los datos enviados mediante POST y GET en HTML con PHP

Como vemos en el ejemplo, formaremos una URL del tipo:

…ac_parte.php?id_eliminar=codigo

Y como hemos explicado anteriormente, dejarla así sería MUY peligroso y poco seguro. Para «encriptar» o «camuflar» los datos enviados mediante la URL,  mediante un POST ó un GET, podemos usar el siguiente método:

En la parte del código anterior, al mostrar el botón y generar la URL de destino, obtendremos el MD5 del código añadiéndole previamente una cadena de caracteres interna que sólo nosotros conoceremos (para mayor seguridad). Para ello podemos crear una función que colocaremos en nuestro fichero PHP de funciones y procedimientos, con una constante llamada «CLAVE» que contendrá la cadena de caracteres que se concatenará al código, para generar un MD5 totalmente irreversible:

Y en la parte de código donde mostramos la tabla HTML de registros podríamos colocar nuestra función:

Como podemos ver en el código, en primer lugar recorremos todos los registros de la tabla «partes», creamos una tabla HTML (mediante una función), y añadimos el botón «Eliminar» a cada registro de la tabla, con la codificación generada por la función «generaURLSegura».

De esta forma la URL quedará de la siguiente forma:

…/ac_parte.php?id_eliminar=fc2387da5940377fa037db069526d59a

Continuando con el proceso de securizar las URL, el siguiente paso será aplicar el MD5 y la concatenación también en la consulta SQL de la base de datos (sea MySQL o MariaDB, en ambas se aplica la misma función). Por ejemplo:

Como vemos en el código, en la sentencia SQL DELETE usamos la función de MySQL md5, le concatenamos el valor de la constante CLAVE al valor del campo codigo de cada registro y comparamos el resultado con el valor pasado con el parámetro id_eliminar mediante la URL y el GET.

Método para camuflar de forma segura los datos enviados mediante POST y GET en HTML con PHP

De esta forma un usuario malintencionado no podría generar una URL y ejecutarla para eliminar otro registro, dado que necesitaría saber obtener el MD5 y, sobre todo, necesitaría la clave que usamos concatenada para la obtención.

Por supuesto, también podríamos «codificar» el nombre de los parámetros (en nuestro ejemplo el id_eliminar), para que tampoco se vea el nombre usado en la URL, aplicando el mismo método que para el valor o aplicándole otro para mayor seguridad, por ejemplo un simple sha1. La función «generaURLSegura» quedaría:

Para mostrar el botón Eliminar quedaría exactamente igual, dado que hemos usado una función «generaURLSegura» que sería la misma pero con resultado diferente. Y para las ejecuciones SQL internas quedaría:

Vemos en el código que aplicamos la función sha1 al texto «id_eliminar» para compararla con el valor pasado por la URL, si coincide quiere decir que el parámetro a aplicar es «id_eliminar». De esta forma la URL quedaría:

…/ac_parte.php?e762fa27f9d8c291da6f8f3aa4d=7b6fa66a4799cc05698bd

Camuflando también al usuario el nombre del parámetro y haciéndola aún más segura.

Hay que decir que tampoco es un método infalible pero, al menos, es mucho más seguro que dejar las URL y los GET sin codificar.

Hay que mencionar que, dependiendo de la configuración de nuestra base de datos MySQL o MariaDB, concretamente del parámetro sql_safe_updates, podemos encontrarnos con este error al ejecutar la consulta SQL con el md5 en el where:

Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column.

Para evitarlo, el valor de la variable sql_safe_updates debe ser 0 (off), podemos establecerlo ejecutando:

Para ver su valor actual podemos ejecutar la consulta SQL:

Más métodos de seguridad que debemos aplicar SIEMPRE en los GET y POST

Por supuesto, el explicado anteriormente en un método para mejorar la seguridad de nuestro sitio web, pero debemos aplicar más métodos de seguridad en los datos que enviamos por parámetros tanto GET como POST. Algunos de los métodos pueden ser:

  • Asegurarnos de limpiar bien los datos obtenidos con POST o GET de posibles inyecciones de SQL. Para esto PHP cuenta con muchas funciones o incluso nosotros podemos crear las nuestras propias. Los datos a tratar nunca deben llevar palabras clave como: «INSERT», «DELETE», «SELECT», ni otras muchas que pueden ser usadas por un usuario malintencionado para intentar inyectar SQL y obtener o modificar datos del servidor. Por lo tanto, si lo que esperamos es un número, deberemos asegurarnos de que sólo se recibe un número. También podemos hacerlo por tamaño, si sabemos que lo máximo que podemos obtener es una cadena de 4 caracteres, deberemos comprobar si es más grande para actuar en consecuencia.
  • Podemos usar las variables de sesión de PHP, que son mucho más seguras y fiables que los métodos POST y GET. No hablamos de sustituir un GET o POST por una variable de sesión, hablamos de usarlas como medida adicional de comprobación, para garantizar, por ejemplo, que el usuario que ejecuta una URL se ha validado contra nuestro servidor y es un usuario fidedigno.
  • Es conveniente establecer niveles de seguridad por usuario, comprobando siempre antes de hacer un INSERT, UPDATE o DELETE si el usuario actual tiene permisos para ello en la tabla de destino.