Siempre que hagamos una aplicación web, tenemos que tener muy encuenta las cuestiones de seguridad, sobre todo las formas más conocidas de ataque. Una de estas formas es Cross-Site Request Forgeries, que más o menos viene a decir Falsificación de Petición desde Otro Sitio (quizás la traducción no es exacta, pero creo que lo explica bien).
Este ataque se produce cuando a un usuario se le conceden permisos, confiando en él, pero no teniendo en cuenta que otra gente pueda aprovecharse de ello. Supongamos que tenemos una página de compra de artÃculos, cuya aplicación controla perfectamente los campos de entrada y que tiene una función que realiza la operación de compra de artÃculos.
Tenemos el formulario HTML:
<form action="compra.php" method="POST">
ArtÃculo: <input type="text" name="articulo" />
Cantidad: <input type="text" name="Cantidad" />
<input type="submit" value="Comprar" />
</form>
El primer fallo que solemos cometer es leer las variables de entrada mediante $_REQUEST:
<?php
session_start();
if (isset($_REQUEST['articulo'] &&
isset($_REQUEST['cantidad'])) {
compra($_REQUEST['articulo'],
$_REQUEST['cantidad']);
}
?>
Una forma muy utilizada para realizar un ataque y que al autor del artÃculo le gusta mucho, es mediante el uso de una imagen:
<img src="http://ejemplo.org/compra.php?articulo=CAFETERA&cantidad=1000" alt="ads" />
Con esto conseguimos que el usuario que visita nuestra página tambien haga una petición a la página en cuestión sin que él lo sepa, claro, que esto solo funciona si el usuario a la vez tiene una sesión abierta en la página que se está atacando.
La solución es añadir una marca formada por un número “encriptado” y un tiempo para que tenga que renovarse esta marca. La marca se debe crear y pasar en el formulario por el que se envÃan los datos y a parte se debe controlar su existencia, si coincide y si no ha superado el timeout.
<?php
$marca = md5(uniqid(rand(), TRUE));
$_SESSION['marca'] = $token;
$_SESSION['tiempo_marca'] = time();
?>
<form action="compra.php" method="POST">
<input type="hidden" name="marca" value="<?php echo $marca; ?>" />
ArtÃculo: <input type="text" name="articulo" />
Cantidad: <input type="text" name="Cantidad" />
<input type="submit" value="Comprar" />
</form>
<?php
if ($_POST['marca'] == $_SESSION['marca']) {
$diferencia_tiempo_marca = time() - $_SESSION['tiempo_marca'];
if ($diferencia_tiempo_marca <= 300) {
/* Menos de 5 minutos */
}
}
?>
ArtÃculo original: Security Corner: Cross-Site Request Forgeries
VÃa / backdraft
Todo bien, pero el navegador que utilizas no tiene pestañas..??
Me gusta la idea 😉
Pero le harÃa un cambio para hacer el snippet más “WordPress compliant” 🙂
Puedes sustituir todas las condiciones del primer if por esta más sencilla:
$current_screen->id = 'post'Upss! me deje un =, serÃa:
$current_screen->id == ‘post’
Para que no salgan los nuevos enlaces en el listado de posts, sólo en la de edición del post.
Gracias Samuel, pero el script solo sale en la edición de posts, ya que evalua esta condición:
$_GET[‘action’] == ‘edit’
Eso sÃ, seguro que al script le faltan muchas cosas 🙂
Gracias
Gracias a ti por la idea 😉
SÃ, si el script sólo sale en la edición de posts… tanto el original como con la modificación que te propongo.
Únicamente que en el primer comentario puse sólo un
=y asà sà que darÃa el problema de salir también los listados, de ahà mi segundo comentario, poniendo==sale sólo en la ventana de edición. Y no es necesario hacer se pedazo de if que haces 😉Yo es que soy muy fanático de usar siempre los métodos que proporciona WordPress en lugar de hacerlo con php “estándar”. Porque asà siempre tienes más opciones de compatibilidad futura e incluso de mejor rendimiento.
Pero vamos, que sÃ, que el script funciona igual en su formato original 😀