2009-04-22 8 views
30

J'ai actuellement un lien de connexion sur mon application qui ressemble à ceci:ReturnUrl dans ASP.NET MVC

<a href="/login?ReturnUrl=" + <%= Request.RawUrl %>>Login</a> 

Je veux gérer la commande POST sur la page de connexion dans l'action du contrôleur ci-dessous:

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Login(string returnUrl) 
{ 
    // Authenticate user 

    return Redirect(returnUrl); 
} 

le problème ici est de savoir si le RawUrl est quelque chose avec plusieurs paramètres d'URL comme « somepage? param1 = 1 & param2 = 2 & param3 = 3 », le returnUrl qui est passé dans l'action de connexion est tronquée après la première esperluette: "une page? p aram1 = 1 ".

J'ai essayé UrlEncoding RawUrl mais cela semble faire une différence. Il semble que le framework ASP.NET MVC est ici UrlDecoding les paramètres url avant de les mapper aux paramètres d'action du contrôleur, ce qui finit par enlever les paramètres d'URL supplémentaires que je veux voir dans mon paramètre returnUrl.

Y a-t-il un moyen de contourner ce problème? Je sais que je pourrais juste utiliser Request.Path et analyser les valeurs dont j'ai besoin, mais j'ai pensé que je verrais d'abord s'il y avait une approche plus propre.

Répondre

36

Vous avez probablement mal codé les liens. Oui, ils doivent être encodés. Voici comment nous le faisons:

<a href="<%= Url.Action("Delete", "TimeRecord", 
    new RouteValueDictionary(new { id = timeRecord.AltId, 
    returnUrl=ViewContext.HttpContext.Request.Url.PathAndQuery })) %>"> 
+2

C'est bon; PathAndQuery n'inclut pas le domaine, donc vous n'êtes pas vulnérable à un attaquant utilisant votre serveur pour rediriger vers leur site. – Will

+6

Je ne dirais pas que vous n'êtes pas vulnérable. Les gens peuvent changer les données de formulaire avec Fiddler et autres. Vous devez toujours nettoyer l'URI sur le serveur. D'un autre côté, il est bon de ne pas pré-remplir le formulaire avec de mauvaises données. :) –

+0

Ça a l'air bien. Attention cependant que 'ViewContext.HttpContext.Request.Url' peut retourner null, ce qui signifie que vous pouvez avoir une' NullReferenceException'. –

-2

D'accord, votre solution a une odeur; Je ne peux pas mettre le doigt sur un lien décrivant l'attaque (il doit s'agir d'un détournement de session), mais rediriger aveuglément via une chaîne de requête doit être un trou de sécurité. Quelqu'un répond ou commente avec l'info, pls. Sans tenir compte de l'aspect de sécurité, une solution rapide serait de coder Base64 l'URL de retour entière. Voici un code que je complètement ganked de a blog qui peut ou peut ne pas fonctionner:

public static string ToBase64(this HtmlHelper me, string toEncode) 
{ 
     byte[] toEncodeAsBytes 
      = System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode); 
     string returnValue 
      = System.Convert.ToBase64String(toEncodeAsBytes); 
     return returnValue; 
} 

public static string FromBase64(this HtmlHelper me, string encodedData) 
{ 
     byte[] encodedDataAsBytes 
      = System.Convert.FromBase64String(encodedData); 
     string returnValue = 
     System.Text.ASCIIEncoding.ASCII.GetString(encodedDataAsBytes); 
     return returnValue; 
} 
+2

Je pense que l'attaque va quelque chose comme: http://login.ebay.com/?returnUrl=www.MyFakeSiteThatLooksLikeEbay.com/lolyourescrewed.html alors les gens cliquent sur votre lien, se connectent sur ebay, et sont redirigés vers votre faux site qui ressemble à ebay où vous demanderez à l'utilisateur de confirmer les informations de sa carte de crédit. – Will

+0

Cela a du sens. La solution que Craig Stuntz a publiée corrige cette situation en utilisant PathAndQuery à la place. –

+2

Non, ça passe: ça passe de belles données sans domaine, mais ça ne répond pas au fait que si quelqu'un vous a passé des données AVEC un domaine, vous devez encore valider l'entrée dans la méthode du contrôleur – Jaykul

8

Assurez-vous de l'URL encode la RawUrl avant de l'utiliser.

<%= Url.Encode(Request.RawUrl) %> 

Cela devrait le faire pour vous.

+2

C'est la bonne façon de le faire. – ajma

+0

Comme l'indique la question initiale, cela ne fonctionne pas. –

+0

Cela fonctionne très bien, le poste d'origine mal analysé ce qui se passait. –