2011-03-01 9 views
5

que tiene una acción en mi sitio:Prevenir Salir Acción suceda a partir de fuentes no confiables en PHP

http://mysite.com/User/Logout 

Esto registrará el usuario actual de su/su sesión. Como se trata de una solicitud GET simple, un usuario malintencionado podría crear enlaces a esta página o incluso poner este enlace en el atributo src de una imagen que obligaría a los usuarios a cerrar la sesión. Todavía me gustaría mantener la simplicidad del enlace de cierre de sesión sin tener que ir demasiado lejos, pero al mismo tiempo me gustaría poder evitar que ocurra el escenario anterior.

¿Alguna idea?

Respuesta

5

Bueno, hay algunas opciones que usted puede hacer para ayudar a proteger contra los ataques CSRF:

  1. utilizar una forma y una muestra aleatoria. Así que en lugar de tener un "enlace", utilizar un testigo aleatorio que se ha configurado en la sesión en una forma

    <form action="/User/logout" method="post"> 
        <submit name="logout" value="Logout" /> 
        <input type="hidden" name="token" value="<?php echo getSessionToken(); ?>" /> 
    </form> 
    

    Tenga en cuenta que POST es mejor para este tipo de acción, pero que podría cambiar la forma de un GET sin demasiado mucha molestia.

    Luego, en php, simplemente:

    if (getSessionToken(true) != $_POST['token']) { 
        die('CSRF!'); 
    } 
    

    Tenga en cuenta que getSessionToken debería funcionar algo como esto:

    function getSessionToken($reset = false) { 
        if (!isset($_SESSION['random_token'])) { 
         $_SESSION['random_token'] = sha1(uniqid(mt_rand(), true)); 
        } 
        $token = $_SESSION['random_token']; 
        if ($reset) { 
         unset($_SESSION['random_token']); 
        } 
        return $token; 
    } 
    

    También tenga en cuenta que cada vez que buscar a los contadores a comprobarlo, debe restablecerla a algo nuevo (que es lo que hace esto). Esto evita los ataques de repetición cuando un atacante detecta el token en el envío y vuelve a enviar el valor.

  2. Si debe usar un enlace, incruste el token en el enlace. Pero tenga en cuenta que esto es más susceptible al ataque ya que existe la posibilidad de que el usuario copie y pegue el enlace a otra persona. Siempre que sea un token de restablecimiento automático, no debería haber muchos problemas con varias pestañas. Pero tenga en cuenta que no es óptimo:

    <a href="/User/logout?token=<?php echo getSessionToken(); ?>">Logout</a> 
    

    Es absolutamente mejor que nada. Pero aún sugeriría usar el formulario para la mejor protección.

me habría altamente sugerir la lectura y después de la OWASP CSRF Guidelines para la prevención de CSRF. Se le dice casi todo lo que necesita saber, y por qué ...

+0

Gran explicación. Es bueno saber que las personas realmente escriben código de seguridad en PHP. Atentamente. – Zed

+0

Hmm, no creo que tu getSessionToken realmente reinicie la variable de sesión 'random_token'. Parece que solo asigna un nuevo token si aún no existe. Si uno existe, sin embargo, nunca asigna uno nuevo. – Scott

+0

@Scott: buen descubrimiento. Fijo... – ircmaxell

0

Sin cambiar el método HTTP, podría agregar un id. Único a la sesión de los usuarios y anexarlo al enlace de desconexión. Si se realiza una acción de cierre de sesión y los dos identificadores coinciden, el cierre de sesión es válido. De lo contrario no lo es!

0

¿Reescribir para leer como/Cerrar sesión? # NONCE #, # NONCE # es un valor que cambia de la solicitud a la solicitud.

+0

... que se romperá si el usuario abre una segunda ventana. – symcbean

+0

Lo cual es un buen porcentaje del punto, y no debería involucrar nada más que redirigir al usuario a una nueva página con un nuevo nonce con el que puede cerrar la sesión. Es una compensación entre la molestia de obtener una broma cerrada y la página volver a cargar sin que usted cierre la sesión usted mismo. –

5

Si cierra la sesión de personas usando las solicitudes GET (o hace algo más importante que eso usando solicitudes GET, para ese asunto), entonces su sitio web será vulnerable a ataques de falsificación de solicitudes entre sitios. Deberías usar POST para desconectar personas. GET es solo para acciones idempotentes, vea RFC 2616 section 9.1.

Tenga en cuenta que al usar GET en este caso no es compatible con el RFC, no es todo lo que necesita cambiar para evitar el XSRF. Ver this answer by ircmaxell para una excelente explicación.

+1

Un buen sitio que encontré hace unos años que detalla algunas técnicas de prevención de CRSF: http://www.aachen-method.com/. Él hace un muy buen trabajo de desglosarlo si no lo entiendes. –

+0

Esta respuesta es lo que necesita. Y la información sobre CSRF debe leerse porque todos sus formularios deben estar protegidos. – Arkh

+0

Sí, este parece ser el camino correcto a seguir. GET fue el método incorrecto aquí. – Scott

0

Vas a tener que requerir algún tipo de validador para pasar a la página de cierre de sesión. Y debe ser calmante, único en la sesión y difícil de adivinar. Ahora, si hubiera un valor adecuado ... oh sí, el identificador de sesión.

Tenga en cuenta que debe utilizar cookies para la gestión de sesión, y debe establecer el indicador http only en la cookie de sesión, por lo que deberá completar el enlace desde PHP (o copie javascript legible cookie).

<?php 
    session_start(); 
    if ($_GET['logout_valid']!==session_id()) { 
     // handle invalid logout request 
     exit; 
    } else { 
     $_SESSION=array(); 
     session_destroy(); 
    } 
0

supongo que soy tarde a la fiesta, pero, aquí es cómo lo manejo:

<?php 

session_start(); 

function logoutButton($name = 'logout', $action = '/User/logout'){ 
$random_token = md5(uniq_id()); 
$_SESSION['csrf'] = $random_token; 
$form = '<form ><input type="hidden" value="'. $random_token .'" name="' .$name. '"><input type="button" value="logout"><</form>'; 
return $form; 
} 

public static isValidRequest($name = 'logout'){ 
if(isset($_POST[$name]) && $_POST[$name] === $_SESSION['csrf']){ 
    return true; 
} 
return false; 
} 

} 
?> 

para mostrar un cierre de sesión botón

echo logoutButton(); 

para cerrar la sesión de forma segura un usuario

if(isValidRequest()){ 
    //logout 
} 

espero que es útil a alguien.

editar: Aquí está una clase creé https://github.com/sahithvibudhi/PHP-CSRF-Protection-class

Cuestiones relacionadas