J'ai un projet sur lequel je travaille et j'ai récemment décidé d'ajouter un "rebond de connexion" sur mon site. L'idée est simple et très courante: l'utilisateur navigue sur le site et se heurte à un problème pour lequel il doit se connecter. Une fois connectés, ils sont renvoyés à leur état antérieur.
Ceci est, bien sûr, ridiculement facile à mettre en œuvre. Mon lien de connexion fournit uniquement l'emplacement d'origine dans une variable de requête et ma page de connexion redirige vers cet emplacement après avoir réussi à utiliser l'en-tête "Location:". Ceci est très simple et ne nécessite aucun état côté serveur.
Cependant, la sécurité me préoccupe toujours, en particulier pour mes utilisateurs. Je souhaite donc prendre des mesures pour les protéger contre la redirection vers des emplacements arbitraires. (Voir https://www.owasp.org/index.php/Top_10_2010-A10-Unvalidated_Redirects_and_Forwards )
Ma solution est très simple: après avoir lu la variable de requête, si l'URL ne commence pas par "/", je la rejette. (L'utilisateur est alors envoyé à une page par défaut.) Cela est basé sur le principe qu'une URL relative doit pointer vers mon site et que les seules URL pouvant commencer par "/" sont relatives. Mon site ne générera jamais que des URL relatives, je suis donc d'accord avec ce schéma plutôt restrictif. (En outre, avec ce schéma, je peux facilement le rendre encore plus étroit en ajoutant le protocole et mon domaine à l'URL. Je pourrais même ajouter à la liste blanche d'autres domaines ultérieurement.)
La redirection uniquement vers les URL commençant par "/" est-elle suffisante? Existe-t-il un moyen d'abuser d'envoyer un utilisateur quelque part en dehors de mon site? Si oui, comment pourrais-je l'éviter?
Un peu plus de contexte: j'utilise PHP, mais je ne pense pas que ce soit vraiment important pour le cœur de la question. Le site accède aux contrôles sur toutes les pages et toutes les URL à l'origine d'une action sont protégées contre les CSRF. L'utilisateur peut ainsi être envoyé n'importe où sur mon site sans conséquences négatives.
Les redirections non validées semblent présenter deux principaux dangers:
Cependant, je crois que j'ai évité ces problèmes: - Mon script autorise uniquement la redirection vers mon propre site, ce qui signifie que je n'ai besoin que d'une protection contre les URL dangereuses sur mon propre site. Sur cette note ... - Je construis déjà mon site pour qu'il soit durci contre les CSRF, il ne devrait donc pas y avoir d'URL dangereuses à exploiter. (Même pas une URL de déconnexion.) Même si l'utilisateur est envoyé sur "intéressant.php", rien ne se passera, la requête étant mal formée. (Toute action sur le site nécessite une action délibérée de l'utilisateur.) Je vais également supprimer les chaînes de requête de l'URL, bien que je ne les utilise pas pour des tâches importantes.
Il me semble donc que la pire chose qui puisse arriver avec une URL manipulée est que l'utilisateur soit envoyé sur une page inattendue. (Ou peut-être un 404.) Ce raisonnement est-il imparfait?
La redirection uniquement vers les URL commençant par "/" est-elle suffisante?
Si vous transmettez l'URL à rediriger en tant que paramètre d'URL, vous devez toujours le valider (ou au moins le nettoyer) autant que possible. Supprimez tous les caractères étranges, effacez (ou validez) la chaîne de requête, etc. Vous devriez également créer une URL absolue pour votre en-tête Location:
, si ce n'est déjà fait.
Vous pouvez également transmettre un hachage de validation dans l'URL afin d'empêcher toute falsification. Ou tout simplement inclure "l'id de la page" à rediriger (pas l'URL), et rechercher l'URL dans votre base de données?
Cependant, personnellement, je n’utiliserais pas un paramètre d’URL pour cette information. Je voudrais stocker cela dans la session en cours à la place. C’est beaucoup plus facile à gérer et intrinsèquement plus sûr. Toutefois, en fonction du lieu où vous obtenez l'URL à rediriger (si elle est simplement extraite de la demande en cours ou s'il s'agit d'une URL canonique reconnue), vous devez toujours au moins nettoyer l'URL avant de procéder à la redirection.