Hiding Query String Parameters - asp.net-mvc-3

I have a GET action for creating records. Because the page is somewhat dynamic, I don't use a model to hold the data. I go off to do some OAuth, only to return to the create screen later on. In order to pass the data back, I am redirecting with a query string. I parse the query string in the GET action, and then show the view. The thing is, the query string is showing up in the browser. This displays pseudo-sensitive data.
Since I am only using the query string for transferring data, I am wondering if I can throw the query string away to prevent it from showing up on the browser.
Otherwise, is there a way to go to another action without redirecting? I've found, if I call the "other" action method directly, it tries to find the view of the original action. I can explicitly change the return View(viewModel) line to return View("create", viewModel) but that seems really dirty.

You should consider changing the action to accept POST requests. At least this will prevent the sensitive information from appearing in the browser. For extra security, your site should be served via SSL.
The other thing you can try is encrypting the sensitive values or the entire query string. The only problem is that this, too, will be preserved in the browser's history unless you require users to log in.

It looks like your action method is trying to do too much. Authentication/authorization is a separate concern which should not be part of the action method. It is better to move the authentication work in to an action filter.
Create an class that extends authorization attribute and override its OnAuthorization method to do your authorization work.
This frees your controller action method to accept POST requests.

Related

Symfony2 and filter, right strategy

I'm asking what is the best strategy for filtering with Symfony2.
I want to filter a table of entities (hotels). This filter should allow me to :
choose hotels with or whitout email, with or without web site etc.
choose hotels based on state and/or city (relation OneToMany)
choose what information I want to display on the table with checkboxs (for example display "email adress" on the hotel table, but do not display "tel" or "web site").
First I think to build the filter form on the HotelController. When the filter is submitted, I had a FlashBag for every $_POST sended, redirect to the same page, and if there are FlashBag I send cookies to the $reponse. Then I display the table filtered with data who are on the cookie.
But I dont't really like this, cause I had a very big indexAction() on the HotelController, and I think it'as not really clean to change $_POST to FlasBag to Cookie, is it ? I do this redirection, cause by refreshing the page, data are not posted again.
I'm also asking a question, to prevent a too big IndexAction() method, can I put some code to another method, for exemple a method PostToFlashBag() and another FlashBagToCookie(), or every method on a Controller has to end with the word "Action" and must be accessible with the router ?
Then, I think to another thing : had an entity "Filter", with every row I need. For exemple "WithEmail", "DisplayTel" etc.. Then I can build a FilterType easily, and update the Filter entitie, to redirect to the same page (again, to prevent reposting data if the user refreshes the page). Finally, I can display the table with the object Filter, with a method on the HotelRepository.
That seems great, but I'm a little worry because the filter entity will only have one entry, and I have to find the Filter(1). Due to MVC, is it correct to have a model with only one entry ?
What strategy would you choose (maybe another one) ? I'm interesting to learn good practice with MVC and Symfony2 devloppemnt.
Having a dedicated model class - let's call it Filter - that will receive the values input by the user, is definitely the way to go.
More over, use the Symfony2 form on this input, so you can have validation, and be sure that the withEmailis trully a boolean, etc. From you Filter, build you SQL/Doctrine query and return what your controller have to return, be it a view, or raw datas.
You can have any method you want in a controller. After all, controllers in Symfony2 are plain old PHP objects. They only have to implement ContainerAwareInterface. Usually they inherits Controller, but this inheritance only brings some proxy methods, like getDoctrine or render.
The only convention is that methods which are used as route must end with Action

When using Url.RouteUrl, the area is missing

I suspect I'm doing this wrong.
For various reasons, my app forces the user to make some choices right after login. In order to ensure that they enter the necessary data, I override the OnActionExecuting method in a base controller class to intercept any attempt at executing an action before this data has been entered, and redirect the user to the necessary page. I preserve the url of the action they were attempting to execute with the following code:
url = Url.RouteUrl("Default", filterContext.RouteData.Values);
(filterContext is an ActionExecutingContext object, and a parameter of OnActionExecuting.)
The problem I'm having is that, if the action was associated with a controller in an area, the url I get doesn't reflect the area.
I understand from other posts that I can get the area name from the DataTokens collection of RouteData. But I'm uncertain of the best way to pass it. I suppose I could retrieve it and use the RouteValueDictionary.Add method to add it to RouteData.Values (assuming Values is not read-only at that point; I don't know), but that feels a bit ... odd, like somehow the point is being missed.
Is this really the way this is supposed to be done? Is there something wrong elsewhere, that Area is absent from my RouteData.Values?
I would just take it out of the data tokens in the filter and add it to route values. You can do it with RouteValues.Add:
if (filterContext.RouteData.DataTokens.ContainsKey("area"))
filterContext.RouteData.Values.Add("area",
filterContext.RouteData.DataTokens["area"]);
The areas feature was added in MVC2, and I imagine this is a side effect of it not being in MVC1. However, as long as your RouteValues contains an "area" key, UrlHelper.RouteUrl should generate the correct URL for the area.

Hide url routing parameters in asp.net mvc

Is there a method for specifically hiding the routing parameters in ASP.NET MVC from the users. Specifically, I'd like a link
http://sitename.com/Do?title = 2
to simply become
http://sitename.com/Do
but internally pass the titleId to my controller.
Is that do able?
Thanks
Update: yes, there are buttons on my webpage that currently have such as their href, but I'd rather hide all the parameters so users dont go to other parts of the page directly by trying differnt parameters. #Moshe, no its not a from submit or post else I'd have used a strongly typed view. Thanks
As long as your parameters are on the client, they are never 'hidden' unless you encrypt them. You could store the parameter in a hidden field and set the action method to post, then the value is not visible in the URL. But a user with a little bit of knowlegde about web could still manipulate the hidden field (unless you encrypt the value in some way).
EDIT: If it has to be save you have to check the user's credentials on the server. Otherwise you can obscure the data like in the other sample or you can use encryption, e.g. with ProtectData.Protect(...).
For simple numeric values that have to be passed back and forth to a view you can write two private methods in your controller:
private int Obscure(int source) {
return (source*source) * 3; //or something clever you come up with
}
private int DeObscure(int obscuredValue) {
return (int)Math.Sqrt(obscuredValue / 3); //inverse the Obscure method
}
You can use these to obscure values before you pass them to a view, and de-obscure them after you get them posted back. Mind you, this is really not a good way to implement security, as is explained in this stackoverflow post.
Another option is to create an Obscure/DeObscure procedure that takes in the entire querystring and somehow mangles that back and forth. This would required writing a custom ViewEngine though. Sounds interesting...

Make the route parameter actually appear in the address bar

I have a tiny application in MVC 3.
In this tiny application, I want my URLs very clear and consistent.
There's just one controller with one action with one parameter.
If no value is provided (that is, / is requested by the browser), then a form is displayed to collect that single value. If a value is provided, a page is rendered.
The only route is this one:
routes.MapRoute(
"Default",
"{account}",
new { controller = "Main", action = "Index", account = UrlParameter.Optional }
);
This all works fine, but the account parameter never appears in the address line as a part of the URL. I can manually type test.com/some_account and it will work, but other than that, the account goes as a post parameter and therefore does not appear. And if I use FormMethods.Get in my form, I get ?account=whatever appended to the URL, which is also not what I want and which goes against my understanding. My understanding was that the MVC framework would try to use parameters set in the route, and only if not found, it would append them after the ?.
I've tried various flavours of setting the routes -- one route with a default parameter, or one route with a required parameter, or two routes (one with a required parameter and one without parameters); I've tried mixing HttpGet/HttpPost in all possible ways; I've tried using single action method with optional parameter string account = null and using two action methods (one with parameter, one without), but I simply can't get the thing appear in the URL.
I have also consulted the Steven Sanderson's book on MVC 3, but on the screenshots there are no parameters either (a details page for Kayak is displayed, but the URL in the address bar is htpp://localhost:XXXX/).
The only thing that definitely works and does what I want is
return RedirectToAction("Index", new { account = "whatever" });
But in order to do it, I have to first check the raw incoming URL and do not redirect if it already contains an account in it, otherwise it is an infinite loop. This seems way too strange and unnecessary.
What is the correct way to make account always appear as a part of the URL?
My understanding was that the MVC framework would try to use
parameters set in the route, and only if not found, it would append
them after the ?
Your understanding is not correct. ASP.NET MVC doesn't append anything. It's the client browser sending the form submission as defined in the HTML specification:
The method attribute of the FORM element specifies the HTTP method used
to send the form to the processing agent. This attribute may take two
values:
get: With the HTTP "get" method, the form data set is appended to the URI specified by the action attribute (with a question-mark ("?")
as separator) and this new URI is sent to the processing agent.
post: With the HTTP "post" method, the form data set is included in the body of the form and sent to the processing agent.
ASP.NET MVC routes are used to parse an incoming client HTTP request and redispatch it to the corresponding controller actions. They are also used by HTML helpers such as Html.ActionLink or Html.BeginForm to generate correct routes. It's just that for your specific scenario where you need to submit a user entered value as part of the url path (not query string) the HTML specification has nothing to offer you.
So, if you want to fight against the HTML specification you will have to use other tools: javascript. So you could use GET method and subscribe to the submit handler of the form and inside it manipulate the url so the value that was appended after the ? satisfy your requirements.
Don't think of this as ASP.NET MVC and routes and stuff. Think of it as a simple HTML page (which is what the browser sees of course) and start tackling the problem from that side. How would you in a simple HTML page achieve this?

GET vs POST in AJAX?

Why are there GET and POST requests in AJAX as it does not affect page URL anyway? What difference does it make by passing sensitive data over GET in AJAX as the data is not getting reflected to page URL?
You should use the proper HTTP verb according to what you require from your web service.
When dealing with a Collection URI like: http://example.com/resources/
GET: List the members of the collection, complete with their member URIs for further navigation. For example, list all the cars for sale.
PUT: Meaning defined as "replace the entire collection with another collection".
POST: Create a new entry in the collection where the ID is assigned automatically by the collection. The ID created is usually included as part of the data returned by this operation.
DELETE: Meaning defined as "delete the entire collection".
When dealing with a Member URI like: http://example.com/resources/7HOU57Y
GET: Retrieve a representation of the addressed member of the collection expressed in an appropriate MIME type.
PUT: Update the addressed member of the collection or create it with the specified ID.
POST: Treats the addressed member as a collection in its own right and creates a new subordinate of it.
DELETE: Delete the addressed member of the collection.
Source: Wikipedia
Well, as for GET, you still have the url length limitation. Other than that, it is quite conceivable that the server treats POST and GET requests differently; thus the need to be able to specify what request you're doing.
Another difference between GET and POST is the way caching is handled in browsers. POST response is never cached. GET may or may not be cached based on the caching rules specified in your response headers.
Two primary reasons for having them:
GET requests have some pretty restrictive limitations on size; POST are typically capable of containing much more information.
The backend may be expecting GET or POST, depending on how it's designed. We need the flexibility of doing a GET if the backend expects one, or a POST if that's what it's expecting.
It's simply down to respecting the rules of the http protocol.
Get - calls must be idempotent. This means that if you call it multiple times you will get the same result. It is not intended to change the underlying data. You might use this for a search box etc.
Post - calls are NOT idempotent. It is allowed to make a change to the underlying data, so might be used in a create method. If you call it multiple times you will create multiple entries.
You normally send parameters to the AJAX script, it returns data based on these parameters. It works just like a form that has method="get" or method="post". When using the GET method, the parameters are passed in the query string. When using POST method, the parameters are sent in the post body.
Generally, if your parameters have very few characters and do not contain sensitive information then you send them via GET method. Sensitive data (e.g. password) or long text (e.g. an 8000 character long bio of a person) are better sent via POST method.
Thanks..
I mainly use the GET method with Ajax and I haven't got any problems until now except the following:
Internet Explorer (unlike Firefox and Google Chrome) cache GET calling if using the same GET values.
So, using some interval with Ajax GET can show the same results unless you change URL with irrelevant random number usage for each Ajax GET.
Others have covered the main points (context/idempotency, and size), but i'll add another: encryption. If you are using SSL and want to encrypt your input args, you need to use POST.
When we use the GET method in Ajax, only the content of the value of the field is sent, not the format in which the content is. For example, content in the text area is just added in the URL in case of the GET method (without a new line character). That is not the case in the POST method.

Resources