tags:

views:

2426

answers:

3

I currently have a login link on my application that looks something like this:

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

I want to handle the POST command on the login page in the controller action below:

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

    return Redirect(returnUrl);
}

The problem here is if the RawUrl is something with multiple url parameters like "somepage?param1=1&param2=2&param3=3", then the returnUrl that gets passed into the Login action is truncated after the first ampersand: "somepage?param1=1".

I've tried UrlEncoding the RawUrl but that seem to make any difference. It seems that the ASP.NET MVC framework here is UrlDecoding the url params before mapping them to the controller action parameters, which ends up stripping off the additional url parameters I want to see in my returnUrl parameter.

Is there any way around this? I know I could just use Request.Path and parse out the values I need, but I thought I'd see if there was a cleaner approach first.

+7  A: 

You're probably encoding the links incorrectly. Yes, they do need to be encoded. Here is how we do it:

<a href="<%= Url.Action("Delete", "TimeRecord", 
    new RouteValueDictionary(new { id = timeRecord.AltId, 
    returnUrl=ViewContext.HttpContext.Request.Url.PathAndQuery }) ) %>">
Craig Stuntz
This is good; PathAndQuery doesn't include the domain, so you're not vulnerable to an attacker using your server to redirect to their site.
Will
I wouldn't say you're not vulnerable. People can change the form data with Fiddler and the like. You still have to sanitize the URI at the server. On the other hand, it's good to not pre-populate the form with bad data. :)
Craig Stuntz
Looks good. Beware though that `ViewContext.HttpContext.Request.Url` can return null, meaning that you may have a `NullReferenceException`.
Drew Noakes
A: 

Okay, your solution has a smell to it; I can't put my finger on a link describing the attack (its gotta be a session hijack of some sort), but blindly redirecting via a querystring has GOT to be a security hole. Somebody answer or comment with the info, pls.

Without thinking about the security aspect of this, one quick solution would be to Base64 encode the entire return url. Here's some code I completely ganked from a blog which may or may not work:

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;
}
Will
I'm thinking the attack goes something like: http://login.ebay.com/?returnUrl=www.MyFakeSiteThatLooksLikeEbay.com/lolyourescrewed.html so people click your link, log into ebay, and are redirected to your fake site that looks like ebay where you'll ask the user to confirm their credit card information.
Will
Makes sense. The solution that Craig Stuntz posted addresses this by using PathAndQuery instead.
Kevin Pang
No it doesn't: it passes nice data without a domain, but it doesn't address the fact that if someone passed you data WITH a domain, you still need to validate the input in the controller method
Jaykul
+1  A: 

Make sure you URL encode the RawUrl before using it.

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

This should do it for you.

Nick Berardi
This is the right way of doing it.
ajma
As the original question states, this doesn't work.
gWiz
This works fine, the original post mis-analysed what was happening.
Nick Berardi