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.