¿Es seguro redirigir al parámetro de URL sin filtrar?

7

Una página web redirige a una URL dada en el parámetro redirect sin filtrarla, de esta manera:

$newURL=$_GET["redirect"];
header('Location: '.$newURL);

login.php?redirect=home.php

Si se hace eco de la entrada, sé que es posible realizar un ataque XSS, pero ¿podemos inyectar código cuando solo se usa en el método del encabezado? ¿Es este un script seguro?

    
pregunta Fast Snail 27.04.2016 - 02:54
fuente

4 respuestas

9

La respuesta corta

No. Esto no es seguro, y no debe hacerse. De hecho, este es el último de Top 10 de OWASP :

  

A10. Redirecciones y reenvíos no validados

     

Las aplicaciones web frecuentemente redirigen y reenvían a los usuarios a otras páginas y sitios web, y utilizan datos no confiables para determinar las páginas de destino. Sin la validación adecuada, los atacantes pueden redirigir a las víctimas a sitios de phishing o malware, o usar reenvíos para acceder a páginas no autorizadas.

Phishing y propagación de malware

Un atacante puede crear una URL para redirigir a cualquier página que desee y luego difundirla en todas partes:

http://trusted.com/index.php?redirect=http%3A%2F%2Fmalicious.com

La URL maliciosa se puede ofuscar para evitar que el usuario la detecte mediante la URL que codifica todos los caracteres para obtener una cadena como %68%74%74%70%3A%2F%2F%6D%61%6C%69%63%69%6F%75%73%2E%63%6F%6D .

Ahora, un usuario que haga clic en lo que parece un enlace seguro ordinario a su sitio podría terminar en cualquier lugar:

  • En un sitio que se parece exactamente al tuyo, solicita un nombre de usuario y una contraseña. Boom, las cuentas robadas.
  • Un sitio que propaga malware por unidad por descargas. Podría intentar reclamar que este no es su problema, ya que técnicamente no es su sitio lo que lo propaga. No estoy seguro de que la víctima esté de acuerdo.
  • Simplemente cualquier cosa. ¿Desea que los usuarios hagan clic en los enlaces de su sitio y terminen en contenido ilegal o NSFW o NSFL?

Si esto se hace después de que el usuario inicie sesión, como sugiere en la pregunta, es aún más peligroso ya que el hecho de estar en su página al ingresar las credenciales fortalece la creencia de los usuarios de que realmente está en su sitio. Después del inicio de sesión, sería muy fácil proporcionar un tipo de página de "contraseña incorrecta, inténtelo de nuevo".

Inyección de cabecera

Como ya dijo Steffen Ullrich en su responde a esta pregunta y yo en esto responde a otra pregunta, en las versiones de PHP anteriores a 5.1.2, esto podría usarse para la inyección de encabezados.

Qué hacer en su lugar

Lista blanca o validación

Como suele ocurrir, la solución es la lista blanca. Aquí hay un ejemplo de PHP:

$param = $_GET["redirect"];
$allowed = array(
    "index" => "index.php",
    "blog"  => "blog/index.php",
    // ...and so on...
);
$redirect = isset($allowed[$param]) ? $allowed[$param] : "index.php";
header('Location: '.$redirect);

Esto será tedioso si hay muchas páginas a las que desea poder redireccionar. Dependiendo de la apariencia de sus URL, puede validar las URL de su propio sitio. Por ejemplo, si están en el formulario http://trutsted.com/?pageid=1234 , podría aceptar solo la página a la que redirigir y verificar que en realidad es numérico.

Comprobación de referencia

Si solo desea que los enlaces de redireccionamiento funcionen desde su propio sitio, puede consultar el encabezado de referencia HTTP de la solicitud. Esto podría tener algunos problemas si sirve su sitio a través de HTTP y HTTPS, ya que si se vincula desde una página HTTP a una página HTTPS, no se enviará el encabezado del remitente.

Aquí hay un código de ejemplo:

$headers = apache_request_headers();
$referer = isset($headers['referer']) ? parse_url($headers['referer'], PHP_HOST) : "";
if($referer == "trusted.com") {
    //Do the redirect. If you want your code to be safe on old PHP versions,
    //you will need to filter out newlines or just URL encode the URL.
}
else {
    //Inform the user of the problem or just redirect to your index page.
}

Más lecturas

  • OWASP hoja de trucos sobre redirecciones no validadas. (Uno de los ejemplos sobre cómo no hacerlo aquí es casi idéntico a cómo lo hiciste en tu pregunta).
  • Troy Hunt tiene una excelente pieza sobre este tema.
respondido por el Anders 27.04.2016 - 10:22
fuente
5

Las versiones actuales de PHP detectan y previenen inyecciones de nueva línea en la función de encabezado, consulte Cómo evitar la inyección de encabezado HTTP (nuevos caracteres de líneas) . En versiones anteriores de PHP, probablemente podrías hacer algo como

 login.php?redirect=%0D%0A%0D%0A<script>...

Lo que saldría del encabezado y daría como resultado

 Location:

 <script>...

Y su secuencia de comandos podría hacer lo que quiera, incluido el acceso y el reenvío de cookies de sesión para el secuestro de sesión.

Eso no significa que su script esté seguro con el PHP actual. Redirigir a URLs arbitrarias nunca es una buena idea, por lo que debe restringir newURL a las URL que espera para la redirección.

    
respondido por el Steffen Ullrich 27.04.2016 - 09:03
fuente
2

Para agregar a lo que otros han dicho:

Si tiene un conjunto de direcciones URL conocidas para redireccionar (que podría asignar a un identificador), sería mucho mejor permitir solo identificadores conocidos en el valor del parámetro "redireccionar". Luego, puede asignar el identificador a su URL segura y conocida.

Gracias a tal técnica, "todos tus problemas" desaparecen.

Por supuesto, si el valor de la URL es 100% arbitrario para sus usuarios, o si no tiene el conjunto de todas las URL posibles, esto no puede aplicarse. Pero si su URL corresponde a las páginas conocidas sobre las que tiene control, ¡adelante!

    
respondido por el niilzon 27.04.2016 - 09:33
fuente
1

La primera vulnerabilidad que se me ocurre es pasar una URL completa como un argumento que redirigirá al usuario a una copia falsa del sitio ( login.php?redirect=http://malicious.com )

Aparte de eso, estoy seguro de que hay varias formas de evitar que se produzca la redirección y se muestre en su lugar HTML / JavaScript malicioso.

Como regla general, el parámetro de URL cualquier debe estar limpio.

    
respondido por el user7094 27.04.2016 - 04:55
fuente

Lea otras preguntas en las etiquetas