• Status: Solved
  • Priority: High
  • Security: Public
  • Views: 92
  • Last Modified:

Redirecting after removing one or more query string params.

Need to Redirect after removing one or more query string params.


I am using a whitelist to remove dangerous query string params, and when done, need to redirect to whatever is left in the  query string.

I understand things may break, but am okay letting our website's existing default behavior handle it.

What is the exact command to redirect?

ActionExecutingContext filterContext is the input param of the ActionFilterAttribute

        public override void OnActionExecuting(ActionExecutingContext filterContext)

and after removing the faulty query string params from:

filterContext.HttpContext.Request.QueryString

I am ready to redirect.

                filterContext.HttpContext.Response.Redirect(filterContext.HttpContext.Request.);

Please complete the the above parameter for Redirect()

Thanks
0
newbieweb
Asked:
newbieweb
  • 12
  • 9
1 Solution
 
Kyle AbrahamsSenior .Net DeveloperCommented:
from:  https://stackoverflow.com/questions/3214774/how-to-redirect-from-onactionexecuting-in-base-controller

        filterContext.Result = new RedirectResult(url);
       return;

Open in new window

0
 
newbiewebSr. Software EngineerAuthor Commented:
Yes, but where does url come from?

I have remove faulty params of

               var value = filterContext.HttpContext.Request.QueryString[key];


using the following code

        private void RemoveParameter(NameValueCollection nameCollection, string keyToRemove)
        {
            // reflect to readonly property
            PropertyInfo isreadonly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);

            if (isreadonly != null)
            {
                // make collection editable
                isreadonly.SetValue(nameCollection, false, null);

                // remove
                nameCollection.Remove(keyToRemove);

                // make collection readonly again
                isreadonly.SetValue(nameCollection, true, null);
            }
        }

Open in new window


with the NameValueCollection  param coming from
filterContext.HttpContext.Request.QueryString
0
 
Kyle AbrahamsSenior .Net DeveloperCommented:
filterContext.HttpContext.Current.Request.Url or
filterContext.HttpContext.Current.Request.RawUrl

depending on what you need.
0
Introducing Cloud Class® training courses

Tech changes fast. You can learn faster. That’s why we’re bringing professional training courses to Experts Exchange. With a subscription, you can access all the Cloud Class® courses to expand your education, prep for certifications, and get top-notch instructions.

 
newbiewebSr. Software EngineerAuthor Commented:
I need a string.

But there is no "Current" option available.

and both of these fail:
filterContext.HttpContext.Request.Url
filterContext.HttpContext.Request.Url.ToString()
0
 
Kyle AbrahamsSenior .Net DeveloperCommented:
What do you mean fail?

Are they not available?  Are they null?  

What about RawURL?
0
 
newbiewebSr. Software EngineerAuthor Commented:
Sorry, I saw the squiggly underlining and thought it was an error. It was a warning about a null value.

It runs, but seems to be on an infinite loop, hitting breakpoints inside my Action filter forever.

Should I call the following at the end of the Action Filter?

            base.OnActionExecuting(filterContext);
0
 
Kyle AbrahamsSenior .Net DeveloperCommented:
Do you check if you need to redirect?  That could be the result of your loop.
0
 
newbiewebSr. Software EngineerAuthor Commented:
I only do the redirect after I have removed a failed query param. Otherwise, not.

Is that what you're asking?

    if (badQueryStringKeys.Count > 0)
            {
                filterContext.HttpContext.Response.Redirect(filterContext.HttpContext.Request.Url.ToString()); 
            }

Open in new window

0
 
Kyle AbrahamsSenior .Net DeveloperCommented:
That's what I was asking.  Not sure why you would get an infinite loop then -> can you post your code?
0
 
newbiewebSr. Software EngineerAuthor Commented:
It stopped looping infinitely.

When I removed the following...
    filterContext.Result = new RedirectResult(filterContext.HttpContext.Request.Url.ToString()); 

Open in new window


but loops two times, and crashed out with an error about appending the cookie, when I use this:

    filterContext.HttpContext.Response.Redirect(filterContext.HttpContext.Request.Url.ToString()); 

Open in new window


Here is the entire object:

 public class UrlRedirectValidationAttribute : ActionFilterAttribute
    {
        private List<string> WhiteListValues => new List<string>()
        {
            "mydomain.org"
        };
 
       public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            List<string> badQueryStringKeys = new List<string>();

            foreach (var key in filterContext.HttpContext.Request.QueryString.AllKeys)
            {
                var value = filterContext.HttpContext.Request.QueryString[key];

                if (value.IsAbsoluteUrl())
                {
                    try
                    {                      
                        var url = new Uri(value);

                        if (!url.IsUrlDomainValid(WhiteListValues))
                        {
                            badQueryStringKeys.Add(key);

                        }
                    }
                    catch (ArgumentException ex)
                    {
                        filterContext.Result = GetRedirectResult(filterContext, "Home", "Index");
                    }
                }
            }

            foreach (string badQueryStringKey in badQueryStringKeys)
            {
                RemoveParameter(filterContext.HttpContext.Request.QueryString, badQueryStringKey);
            }

            if (badQueryStringKeys.Count > 0)
            {
                //filterContext.HttpContext.Response.Redirect(filterContext.HttpContext.Request.RawUrl.Split(new[] { '?' })[0]);
                //filterContext.Result = new RedirectResult(filterContext.HttpContext.Request.Url.ToString()); LOOPS
                filterContext.HttpContext.Response.Redirect(filterContext.HttpContext.Request.Url.ToString()); 
            }

            base.OnActionExecuting(filterContext);
        }

        private void RemoveParameter(NameValueCollection nameCollection, string keyToRemove)
        {
            // reflect to readonly property
            PropertyInfo isreadonly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);

            if (isreadonly != null)
            {
                // make collection editable
                isreadonly.SetValue(nameCollection, false, null);

                // remove
                nameCollection.Remove(keyToRemove);

                // make collection readonly again
                isreadonly.SetValue(nameCollection, true, null);
            }
        }

        private ActionResult GetRedirectResult(ActionExecutingContext context, string controller, string action, string clientId = null,
            List<KeyValuePair<string, object>> additionalParameters = null)
        {
            var returnUrl = context.HttpContext.Request.RawUrl;
            var requestAccept = context.HttpContext.Request.Headers["Accept"];
            var dictionary = new RouteValueDictionary
            {
                {"controller", controller},
                {"action", action},
                {"ReturnUrl", returnUrl}
            };
            if (!string.IsNullOrEmpty(clientId))
                dictionary.Add("ClientID", clientId);
            if (additionalParameters != null)
            {
                additionalParameters.ForEach(param => dictionary.Add(param.Key, param.Value));
            }
            return new RedirectToRouteResult(dictionary);
        }
    }
}

Open in new window

0
 
newbiewebSr. Software EngineerAuthor Commented:
Hold the phone!

The following seems to be working...

                filterContext.HttpContext.RewritePath(filterContext.HttpContext.Request.Path);
0
 
newbiewebSr. Software EngineerAuthor Commented:
Perhaps you can comment on whether I even need that function called GetRedirectResult().

I added this so I could at least route to /Home/Index/ in the event there is some unexplained exception.

Does this make sense?
0
 
Kyle AbrahamsSenior .Net DeveloperCommented:
Going back to  your looping - in your code you need to pass in the sanitized url.  
           if (badQueryStringKeys.Count > 0)
            {
                //filterContext.HttpContext.Response.Redirect(filterContext.HttpContext.Request.RawUrl.Split(new[] { '?' })[0]);

                 // I believe this loops because you're passing in the same query string.  You have to redirect to the new, santizied url.              
                filterContext.Result = new RedirectResult(filterContext.HttpContext.Request.Url.ToString()); 
                return;
            }

Open in new window

Rewrite path is used to serve one page as another if that makes sense.  More info on it here: https://msdn.microsoft.com/en-us/library/sa5wkk6d(v=vs.110).aspx 

If it's working for you and you don't care then no sense going down the rabbit hole.

As far as GetRedirectResult I would rename it to GetHomeRedirect() to make it more clear.

And yes it does make sense that in an error you would want the page to go somewhere.  Though I would add some logging or send an email to yourself.

EG:  Hey, we got an error, here's the full URL so you can reproduce and see what's going on.

In theory you shouldn't need it, but theories only survive until you encounter the real world.
0
 
newbiewebSr. Software EngineerAuthor Commented:
Can I avoid that function entirely and the /Home/Index/ redirect simply by using the following line in the Catch?

filterContext.HttpContext.Response.Redirect(filterContext.HttpContext.Request.RawUrl.Split(new[] { '?' })[0]);
0
 
Kyle AbrahamsSenior .Net DeveloperCommented:
filterContext.HttpContext.Response.Redirect(filterContext.HttpContext.Request.RawUrl.Split(new[] { '?' })[0]);

That will redirect to the same page without the query string.

eg:

/somepath/page?goto=XXXX

filterContext.HttpContext.Request.RawUrl.Split(new[] { '?' })[0] = /somepath/page
The home function will go to the actual home path.
0
 
newbiewebSr. Software EngineerAuthor Commented:
> That will redirect to the same page without the query string.

Isn't that the safest thing to do?
0
 
Kyle AbrahamsSenior .Net DeveloperCommented:
Just depends on your logic.  I don't have enough application context to answer that.
0
 
newbiewebSr. Software EngineerAuthor Commented:
So long as there is no exposure to a hack by using this exceptional redirect, I am okay with it. Is it safe to do?
0
 
Kyle AbrahamsSenior .Net DeveloperCommented:
There shouldn't be any exposure to a hack.  Only exposure would be if you allowed access based on an empty query string or if something else weird was happening.

Basically if your page handles the empty query string and you're okay with that in all context / cases (EG: user logged in / not logged in / errors, etc.) then you're fine to redirect to the same path with the empty query string.
0
 
newbiewebSr. Software EngineerAuthor Commented:
> if your page handles the empty query string

I have been told to let the cookies fall where they may on that. We want safety first.
1
 
newbiewebSr. Software EngineerAuthor Commented:
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Microsoft Exchange Server

The MCTS: Microsoft Exchange Server 2010 certification validates your skills in supporting the maintenance and administration of the Exchange servers in an enterprise environment. Learn everything you need to know with this course.

  • 12
  • 9
Tackle projects and never again get stuck behind a technical roadblock.
Join Now