Asegure sus formularios con claves de formulario

La seguridad es un tema candente. Asegurar que sus sitios web sean seguros es extremadamente importante para cualquier aplicación web. De hecho, paso el 70% de mi tiempo asegurando mis aplicaciones. Una de las cosas más importantes que debemos asegurar son las formas. Hoy vamos a revisar un método para evitar la falsificación de solicitudes en formularios de XSS (secuencias de comandos entre sitios) y entre sitios..

Por qué?

Los datos POST se pueden enviar de un sitio web a otro. ¿Por qué es esto malo? Un escenario simple ...

Un usuario, registrado en su sitio web, visita otro sitio web durante su sesión. Este sitio web podrá enviar datos POST a su sitio web, por ejemplo, con AJAX. Debido a que el usuario ha iniciado sesión en su sitio, el otro sitio web también podrá enviar datos de publicación a formularios seguros a los que solo se podrá acceder después de iniciar sesión..

También debemos proteger nuestras páginas contra ataques usando cURL.

Cómo arreglamos esto?

Con las teclas de formulario! Agregaremos un hash especial (una clave de formulario) a cada formulario para asegurarnos de que los datos solo se procesarán cuando se hayan enviado desde su sitio web. Después de enviar un formulario, nuestro script PHP validará la clave del formulario enviado contra la clave del formulario que hemos establecido en una sesión.

Lo que debemos hacer:

  1. Añadir una clave de formulario a cada formulario.
  2. Almacenar la clave de formulario en una sesión.
  3. Valide la clave de formulario después de enviar un formulario.

Paso 1: Una forma simple

Primero necesitamos un formulario simple para propósitos de demostración. Una de las formas más importantes que tenemos para asegurar es el formulario de inicio de sesión. El formulario de inicio de sesión es vulnerable a ataques de fuerza bruta. Crea un nuevo archivo y guárdalo como index.php en su raíz web. Agregue el siguiente código dentro del cuerpo:

     Asegurar formularios con claves de formulario   

Ahora tenemos una página XHTML simple con un formulario de inicio de sesión. Si desea utilizar claves de formulario en su sitio web, puede reemplazar el script anterior con su propia página de inicio de sesión. Ahora, continuemos con la acción real..

Paso 2: Creando una clase

Vamos a crear una clase de PHP para nuestras claves de formulario. Porque cada página puede contener solo uno de forma clave, podríamos hacer un singleton de nuestra clase para asegurarnos de que nuestra clase se utiliza correctamente. Debido a que crear singletons es un tema OOP más avanzado, omitiremos esa parte. Crear un nuevo archivo llamado formkey.class.php y colóquelo en su raíz web. Ahora tenemos que pensar en las funciones que necesitamos. Primero, necesitamos una función para generar una clave de formulario para poder colocarla en nuestro formulario. En su archivo PHP coloque el siguiente código:

 

Arriba, ves una clase con tres partes: dos variables y una función. Hacemos la función privada porque esta función solo será utilizada por nuestros salidaFunciones, que crearemos más adelante. En las dos variables, almacenaremos las claves de formulario. Estos también son privados porque solo pueden ser utilizados por funciones dentro de nuestra clase.

Ahora, tenemos que pensar en una manera de generar nuestra clave de formulario. Debido a que nuestra clave de formulario debe ser única (de lo contrario no tenemos ninguna seguridad), usamos una combinación de la dirección IP de los usuarios para vincular la clave a un usuario, mt_rand () para que sea única, y la función uniqid () Para hacerlo aún más único. También ciframos esta información con md5 () para crear un hash único que luego podemos insertar en nuestras páginas. Debido a que usamos md5 (), un usuario no puede ver lo que usamos para generar la clave. Toda la función:

 // Función para generar la clave de formulario función privada generateKey () // Obtener la dirección IP del usuario $ ip = $ _SERVER ['REMOTE_ADDR']; // Usamos mt_rand () en lugar de rand () porque es mejor para generar números aleatorios. // Usamos 'true' para obtener una cadena más larga. // Consulte http://www.php.net/mt_rand para obtener una descripción precisa de la función y más ejemplos. $ uniqid = uniqid (mt_rand (), true); // Devuelve el hash return md5 ($ ip. $ Uniqid); 

Inserte el código de arriba en su formkey.class.php expediente. Reemplace la función con la nueva función..

Paso 3: Inserción de una clave de formulario en nuestro formulario

Para este paso, creamos una nueva función que genera un campo HTML oculto con nuestra clave de formulario. La función consta de tres pasos:

  1. Genere una clave de formulario con nuestra función generateKey ().
  2. Almacene la clave de formulario en nuestra variable $ formKey y en una sesión.
  3. Salida el campo HTML.

Nombramos nuestra función outputKey () y hacerlo público, porque tenemos que usarlo fuera de nuestra clase. Nuestra función llamará la función privada. generateKey () para generar una nueva clave de formulario y guardarla localmente en una sesión. Por último, creamos el código XHTML. Ahora agregue el siguiente código dentro de nuestra clase de PHP:

 // Función para generar la clave de formulario public function outputKey () // Genere la clave y guárdela dentro de la clase $ this-> formKey = $ this-> generateKey (); // Almacene la clave de formulario en la sesión $ _SESSION ['form_key'] = $ this-> formKey; // Salida del eco de la clave de formulario "formKey. "" /> ";

Ahora, vamos a agregar la clave del formulario a nuestro formulario de inicio de sesión para asegurarla. Tenemos que incluir la clase en nuestro index.php expediente. También tenemos que iniciar la sesión porque nuestra clase utiliza sesiones para almacenar la clave generada. Para esto, agregamos el siguiente código sobre el doctype y la etiqueta head:

 

El código anterior es bastante autoexplicativo. Comenzamos la sesión (porque almacenamos la clave del formulario) y cargamos el archivo de clase de PHP. Después de eso, comenzamos la clase con nueva formKey (), esto creará nuestra clase y la almacenará en $ formKey. Ahora solo tenemos que editar nuestro formulario para que contenga la clave de formulario:

 
outputKey (); ?>
tipo de entrada = "contraseña" nombre = "contraseña" />

¡Y eso es todo! Porque creamos la función. outputKey (), Solo tenemos que incluirlo en nuestro formulario. Podemos usar claves de formulario en cada formulario simplemente agregando outputKey (); ?> Ahora solo revise la fuente de su página web y podrá ver que hay una clave de formulario adjunta al formulario. El único paso que queda es validar las solicitudes..

Paso 4: Validando

No validaremos todo el formulario; sólo la clave de formulario. La validación del formulario es PHP básico y se pueden encontrar tutoriales en toda la web. Vamos a validar la clave de formulario. Debido a que nuestra función "generateKey" sobrescribe el valor de la sesión, agregamos un constructor a nuestra clase de PHP. Se llamará a un constructor cuando nuestra clase sea creada (o construida). El constructor almacenará la clave anterior dentro de la clase. antes de Creamos uno nuevo; así que siempre tendremos la clave de formulario anterior para validar nuestro formulario. Si no hiciéramos esto, no podríamos validar la clave del formulario. Agregue la siguiente función PHP a su clase:

 // El constructor almacena la clave de formulario (si existe) en nuestra variable de clase. function __construct () // Necesitamos la clave anterior, así que la almacenamos if (isset ($ _ SESSION ['form_key'])) $ this-> old_formKey = $ _SESSION ['form_key']; 

Un constructor siempre debe ser nombrado __construir(). Cuando se llama al constructor, verificamos si una sesión está establecida, y si es así, la almacenamos localmente en nuestro old_formKey variable.

Ahora podemos validar nuestra clave de formulario. Creamos una función básica dentro de nuestra clase que valida la clave de formulario. Esta función también debe ser pública porque la usaremos fuera de nuestra clase. La función validará el valor POST de la clave de formulario contra el valor almacenado de la clave de formulario. Agrega esta función a la clase de PHP:

 // Función que validó la clave de formulario POST datos públicos función validate () // Utilizamos la antigua formKey y no la nueva versión generada if ($ _ POST ['form_key'] == $ this-> old_formKey) // The La clave es válida, devuelve true. devuelve verdadero  else // La clave no es válida, devuelve false. falso retorno; 

Dentro index.php, Validamos la clave de formulario usando la función que acabamos de crear en nuestra clase. Por supuesto, solo validamos después de una solicitud POST. Agregue el siguiente código después de $ formKey = new formKey ();

 $ error = 'Sin error'; // es petición? if ($ _ SERVER ['REQUEST_METHOD'] == 'post') // Valide la clave del formulario if (! isset ($ _ POST ['form_key']) ||! $ formKey-> validate ()) // Form la clave no es válida, muestra un error $ error = '¡Error de clave de formulario!';  else // Haga el resto de su validación aquí $ error = '¡No hay error de clave de formulario!'; 

Creamos una variable $ error que almacena nuestro mensaje de error. Si se ha enviado una solicitud POST, validamos nuestra clave de formulario con $ formKey-> validate (). Si esto devuelve falso, la clave de formulario no es válida y mostramos un error. Tenga en cuenta que solo validamos la clave del formulario; se espera que usted valide el resto del formulario..

En su HTML, puede colocar el siguiente código para mostrar el mensaje de error:

 

Esto hará eco del $ error variable si se establece.

Si inicia su servidor y accede a index.php, Verá nuestro formulario y el mensaje 'No error'. Cuando envíe un formulario, verá el mensaje 'No hay error de clave de formulario' porque es una solicitud POST válida. Ahora intente volver a cargar la página y acepte cuando su navegador solicita que los datos de la POST se envíen nuevamente. Verá que nuestro script genera un mensaje de error: '¡Error de clave de formulario!' ¡Su formulario ahora está protegido contra la entrada de otros sitios web y errores con las recargas de página! El error también se muestra después de una actualización porque se generó una nueva clave de formulario después de que enviamos el formulario. Esto es bueno porque, ahora, el usuario no puede publicar accidentalmente un formulario dos veces.

Código Completo

Aquí está el código PHP y HTML completo:

index.php

 validate ()) // La clave de formulario no es válida, muestra un error $ error = '¡Error de clave de formulario!';  else // Haga el resto de su validación aquí $ error = '¡No hay error de clave de formulario!'; ?>     Asegurar formularios con claves de formulario   
outputKey (); ?>

fomrkey.class.php

 old_formKey = $ _SESSION ['form_key'];  // Función para generar la clave de formulario función privada generateKey () // Obtener la dirección IP del usuario $ ip = $ _SERVER ['REMOTE_ADDR']; // Usamos mt_rand () en lugar de rand () porque es mejor para generar números aleatorios. // Usamos 'true' para obtener una cadena más larga. // Consulte http://www.php.net/mt_rand para obtener una descripción precisa de la función y más ejemplos. $ uniqid = uniqid (mt_rand (), true); // Devuelve el hash return md5 ($ ip. $ Uniqid);  // Función para generar la clave de formulario public function outputKey () // Genere la clave y almacénela dentro de la clase $ this-> formKey = $ this-> generateKey (); // Almacene la clave de formulario en la sesión $ _SESSION ['form_key'] = $ this-> formKey; // Salida del eco de la clave de formulario "formKey. "" /> "; // Función que validó la clave de formulario POST datos públicos función validate () // Usamos la antigua formKey y no la nueva versión generada if ($ _ POST ['form_key'] == $ this-> old_formKey) // La clave es válida, devuelve true. return true; else // La clave no es válida, devuelve false. return false;?>

Conclusión

Agregar este código a cada formulario importante en su sitio web aumentará considerablemente la seguridad de su formulario. Incluso detiene los problemas de actualización, como vimos en el paso 4. Dado que la clave de formulario solo es válida para una solicitud, no es posible realizar una doble publicación..

Este fue mi primer tutorial, ¡espero que te guste y lo uses para mejorar tu seguridad! Por favor, hágamelo saber sus pensamientos, a través de los comentarios. ¿Tienes un método mejor? Haznos saber.

Otras lecturas

  • WordPress también usa claves de formulario (denominándolas Nonces): Wordpress Nonces
  • Siete hábitos para escribir aplicaciones seguras de PHP
  • Síganos en Twitter o suscríbase a la Fuente RSS de NETTUTS para obtener más artículos y artículos de desarrollo web diarios.