A continuación vamos a explicar algunos conceptos básicos de brechas de seguridad más comunes y como solucionarlos mediante PHP permitiendo escribir aplicaciones web un poco más seguras.
Protección contra la inyección de código SQL
Es muy común trabajar contra una base de datos (MySQL, PostgreSQL, Oracle, etc.) y estas consultas dependen de parámetros llegados desde GET o POST, por lo que permitimos al usuario de cada web que en cierta manera modifique las consultas SQL de nuestra web.
Esto podría provocar que un usuario que construya una consulta SQL malintencionada pudiera obtener resultados indeseados, como poder hacer un login en una zona restringida de nuestra web sin conocer ningún usuario / contraseña.
Supongamos la siguiente situación: tenemos un nombre de usuario pruebas y una contraseña clave_pruebas guardados en base de datos. Para realizar la identificador obtenemos los parámetros por POST mediante las variables $_POST['usuario'] y $_POST['clave']. Tras ello realizamos la siguiente consulta SQL:
mysql_query('select id from usuariosWeb where usuario = '".$_POST['usuario']."' and password = '".$_POST['clave']."'');
Si existe un usuario con ese nombre y usuario, es que la identificación es correcta y por tanto debemos hacer el login. Pero sin embargo, si construyésemos el siguiente parámetro
$_POST['clave'] ="m' or 1='1"
podemos observar que nos devuelve un valor válido para identificarse conociendo sólo el nombre de usuario.
Para solucionarlo, tenemos diversos métodos pero lo más cómodo es substituir las comillas simples y dobles de todos los parámetros parámetros POST mediante el siguiente código:
foreach($_POST as $key => $value) { $_POST[$key] = str_replace("'","",$value); $_POST[$key] = str_replace('"','',$value); }
Guardar contraseñas, números de tarjeta de crédito, dirección de correo, etc. de forma segura con MD5 ó SHA1
Para guardar las contraseñas de los usuarios en las bases de datos debemos guardarlas de manera que no puedan ser visibles a simple vista ya que si alguna persona malintencionada consiguiera acceder a la base de datos, además de conseguir el control de nuestra web, además tendrá acceso a información sensible de los usuarios que nos visitan.
Para ello podemos dificultarlo mediante los resúmenes hash MD5 o SHA-1, que aunque se tratan de algoritmos crackeados, por lo menos no mostraremos como texto plano esta información.
Ejemplo:
$a = "clave_pruebas"; echo "clave original: ".$a." "; $b = md5($a); echo "Hash MD5 de la clave original: ".$b." "; $c = sha1($a); echo "Hash SHA-1 de la clave original: ".$c." ";
Como podemos ver, con ello conseguimos ocultar mínimamente la contraseña de cada usuario. Cuando un usuario se identifique con su contraseña, realizaremos el cálculo del hash de su contraseña y compararemos contra la base de datos, no el texto plano de la contraseña, si no del hash.
Uso de variables de sesión y no de cookies
Normalmente, alguna zona de nuestra web necesite acceso mediante usuario y contraseña. Para que el usuario no tenga que introducirlas repetidamente podemos guardarla mediante cookies pero es una práctica muy insegura ya que si lo hiciéramos, esta información es transmitida mediante la red en texto plano y podría ser leída por cualquier persona que realice un sniffing de red o que lea las cookies guardadas en nuestro ordenador mediante un virus o troyano.
Por ello lo mejor es hacer uso de las variables de sesión. Estas variables se guardan en el servidor por lo que en cualquier caso, la información transmitida sólo es sensible la primera vez que se envía y no las sucesivas veces (por tanto esto sería evitable haciendo uso del protocolo HTTPS en vez de HTTP).
Como ejemplo del usuario de variables de sesión, haremos uso de dos archivos. En el primero creamos una variable de sesión:
session_start(); $_SESSION['clave'] = "clave_pruebas";
y en el segundo mostramos el valor en pantalla.
session_start(); echo $_SESSION['clave'];
Suplantación de sesiones (Session hijacking o Man in the middle)
Del uso de variables de sesión se deriva otra posible brecha de seguridad que es una persona malintencionada intente suplantar el cliente de cara al servidor. Cuando iniciamos una sesión, creamos una cookie con un identificador único para esa sesión. Si una persona malintencionada interceptase ese identificador único y mandase esa cookie al servidor, podría suplantar nuestra identidad y tener acceso a nuestras zonas restringidas de la web.
Lo solución ideal sería el uso del protocolo HTTPS que encriptaría toda nuestra conexión, pero si esto no es posible, podemos crear una serie de comprobaciones en las que intentemos asegurarnos de la real identidad de cada usuario.
Para ello podemos guardar una serie de variables de sesión de los datos que el usuario nos proporciona en cada visita, como son la dirección IP o la información de su navegador, etc. Si estos cambian significaría que es un intento de session hijacking y por tanto es un usuario que realiza un ataque. En el siguiente ejemplo tenemos dos archivos, en el que en el primer archivo realizamos un login satisfactorio y guardamos los datos iniciales de dirección IP y tipo del navegador con el que lo hemos hecho:
session_start(); $_SESSION['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR']; $_SESSION['HTTP_USER_AGENT'] = $_SERVER['HTTP_USER_AGENT'];
En pantallas posteriores, comprobaremos si en cada pantalla los datos actuales de dirección IP y datos del navegador se corresponden con los que se realizó el login como usuario en la web:
session_start(); if($_SESSION['REMOTE_ADDR'] != $_SERVER['REMOTE_ADDR'] || $_SESSION['HTTP_USER_AGENT'] != $_SERVER['HTTP_USER_AGENT']) { exit(); }
Parámetros GET/POST explotables
Para finalizar, si hacemos uso de parámetros GET y POST deberemos comprobar siempre que se correspondan con el usuario actual o si tiene permisos.
Por ejemplo, si tenemos un archivo que edita productos llamado editarProducto.php y recibe el parámetro GET idproducto, que se corresponde con el identificador único del producto a editar y llamamos al archivo de la siguiente manera:
http://www.miweb.com/editarProducto.php?idproducto=15
deberemos comprobar en cualquier caso que en primer lugar seamos un usuario registrado y logueado y después que el producto de identificador único 15 corresponde a uno de los productos del usuario logueado.
Comentarios