A causa de un cambio de trabajo (ahora me dedico a la Seguridad Informática) llevo un tiempo sin escribir por el blog. Hoy es un buen día para volver a escribir y qué mejor que dedicarlo al tema que inauguró Grabthiscode, la seguridad web.
En la primera y segunda parte aprendiste a mantener tu web segura de vulnerabilidades a nivel de servidor y a nivel de cliente a un nivel básico. En esta tercera aprenderás un “nuevo” tipo de vulnerabilidad muy de moda (incluso Google la sufrió en Gmail) y algún que otro consejo que nunca viene mal.
Antes de empezar con el tema quiero dejar claro que NO soy un experto en seguridad informática (quizás algún día…), estoy empezando en este mundo y poco a poco voy aprendiendo sobre este tema. En mi trabajo me han recomendado este libro para aprender todo lo relacionado con la seguridad web. Te lo recomiendo encarecidamente si te interesa este mundo o si eres un desarrollador web que se preocupa por la seguridad de sus aplicaciones.
Ya dejo de enrollarme y empiezo con lo que de verdad importa:
CSRF o Cross Site Request Forgery
¿En que consiste el CSRF?
Imagina que en tu web tienes un formulario que envía los datos a una web.php. Imagina que ese formulario sirve para cambiar la password del usuario logueado y que para cambiarla solo necesitas estar logueado (nunca hagas un cambio de contraseña así, asegúrate de pedir contraseña actual SIEMPRE). Ahora imagina que yo creo un link (si el formulario es GET) o una imagen (si es post, sí, puedes insertar código en una imagen…) y se la paso a un usuario que use tu apliación. Ese usuario hace click en el link o abre la imagen sin darse cuenta de lo que está pasando internamente.
¿Lo vas pillando? Al ejecutar esa acción, el usuario ha cambiado su contraseña por otra que tú has elegido. Y sí, es una vulnerabilidad de parte del cliente, no del servidor. Pero es una vulnerabilidad grave. Sino busca por Google que les pasó con su sistema de cambio de contraseña de las cuentas…
Vale, lo entiendo pero…¿Cómo puedo evitarlo?
Una vez entendido el problema, hay mil formas de evitarlo. La más común y “segura” es incluir un token como campo oculto en cada formulario, que vaya enlazado con la sesión y que solo sea válido una vez durante un tiempo determinado.
Una vez envías el formulario, el servidor se encargará de recibir ese token, y comprobar si es válido y si no ha sido usado anteriormente. Con eso evitas que un atacante te prepare un enlace o una imagen con código incrustado.
Muy bien, la parte teórica la entiendo, pero ¡dónde está mi código para copiar y pegar?
<?php
function generarToken($formulario)
{
$salt = "~½@2sfasdP";
// genera token de forma aleatoria
// genera fecha de generación del token
// escribe la información del token en sesión para poder
$_SESSION['AntiCsrf'][$formulario.'_token'] = array('token'=>$token, 'time'=>$tokenTime); return $token;
}
function validarToken($formulario,$token,$time=0)
{
if(!isset($_SESSION['AntiCsrf']['cambiarPassword_token']))//no existe el token en la sesion return false;
if($token != $_SESSION['AntiCsrf']['cambiarPassword_token']['token'])//el token almacenado en la sesion no es el mismo que el recibido
return false;
if($time > 0){//solo en caso que quieras que el token caduque cada cierto tiempo
$token_edad = time() - $_SESSION['AntiCsrf'][$formulario.'_token']['time']; if($token_edad >= $time){
return false;
}
}
unset($_SESSION['AntiCsrf'][$formulario.'_token']);//opcional, borrar el token de la sesion return true;
}
if(isset($_POST['NuevaPassword']))//cambiamos contraseña {
$token = $_POST['token'];
$tokenValido = validarToken('cambiarPassword',$token);
if($tokenValido)
{
//proceder con el cambio de contraseña
}
}
?>
<form action="." method="POST" name="cambiarPassword">
<input type="hidden" name="token" value="<?php generarToken('cambiarPassword'); ?>" />
<input type="NuevaPassword" name="pass" />
<input type="submit" value="Cambiar" />
</form>
Con todo esto ya estarás protegido contra este tipo de ataques.
Por último un consejo, esta vez sobre SQLi; siempre añade a cada variable que uses en el sql las comillas simples <’>. ¿Cuál es la razón de esto?
Incluso la famosa función “mysql_real_escape_string” es vulnerable a inyección de SQL si no usas las comillas simples para la variable que le has pasado a mysql_real_escape_string.
Un ejemplo:
Es cierto que mysql_real_escape_string ayuda a proteger de las inyecciones de mysql, pero al no usar la variable entre comillas simples, un atacante podría escribir en $id:
$id="1;delete from myTable;"
Protegerte de este tipo de ataque es tan simple como usar la variable entre comillas simples:
Y esto es todo por hoy, espero que estos consejos te sirvan para tener un poco más de seguridad en tu apliación web.
Saludos!