Readable data in querystring on HTTP Get - asp.net-mvc

We've had a penetration test on a website and they're saying we shouldn't be passing readable data in a querystring (it's an Email Address).
The querystring is being created by the application when ModelState.isValid fails and it returns the model to the view with a HTTP GET. We are being told the EmailAddress value should be encrypted (the site is SSL).
The penetration result :
GET /Membership/RegisterMe?__RequestVerificationToken=26Oajd6AG17YkHhyZz8-pArBuKEEer7V0b86f0aR_jHXs2JqYRE8NHvhz1zCcKWtQ6eVtxtdkTvC6HjG1ami2d-2CPn8Ieedwc77fIoMB941&EmailAddress=SomeOnesEmail.com
We tried to convert the value after it's submitted by doing the following in the controller, so if validation fails it will returns an encrypted value in the querystring:-
ModelState.Remove("EmailAddress");
model.EmailAddress = Helpers.Encryption.Encrypt(model.EmailAddress);
But it loses the validation messages on the property, for example if it's an invalid email address.

Turns out using HTML Helpers in your View makes it difficult to change Model values on Postback (validation fail). It will always return the original values from the HTML helpers in the form. You can change it like so:-
ModelState.Remove("EmailAddress");
Model.EmailAddress = //new value;
My problem was I needed to keep the EmailAddress value but encrypt it before Postback, so the value is not exposed in the querystring. The above was no good as using ModelState.Remove, you also lose the Validation message (invalid Email Address etc.).
Reason was because of the HTML Helpers in the form - #Html.TextBoxFor. Changed this to
<input type="text" name="EmailAddress">
You can then change the value in the controller before postback and maintain the validation errors
Model.EmailAddress = Encrypt(Model.EmailAddress);
The postback value is encrypted and the appropriate validation error messages are displayed to the user in the View. Then did some simple code in the View to decrypt the Model.EmailAddress.

Related

Why is there a difference in the validateantiforgerytoken cookie value and hidden form value?

I have got the MVC4 [ValidateAntiForgeryToken] attribute working perfectly. However, I don't understand what I am seeing in Fiddler. The cookie sent by the server to the browser is set to this value:
__RequestVerificationToken=FVcmfj07ZEuBdjGuqWu14KIzolxr0ArLgvbNdnq0c4DFywxSA31yIHbm2IzgTPMVhMl4STEh2re8oGmwsSjKtSBTolCsmyGGRnLE1qurUqA1
but the hidden form input is set to this value:
OxjO3NjS1ly-bqP9RnYK9Vx8ZJyLGVCuTQEuSCAQWofVmuJaRkEcnHAHWcDurXaH6DhUiZ6XY5wCgi70u19mPy9sydMrkuS9qlWMXxGL_401
i.e. they appear different where they should match. Am I not understanding cookies properly and perhaps the first string is not the actual 'value' of the cookie encrypted?
Source Pro ASP.NET MVC 3 Framework:
The __RequestVaerificationToken hidden field contains a random component (matching the one in the cookie), but that's not all. If the user is logged in, then the hidden field value will also contain their user name (obtained from HttpContext.User.Identity.Name and then encrypted).
[ValidateAntiForgeryToken] checks that this matches the logged-in user. This adds protection in the unlikely scenario where an attacker can somehow write (but not read) cookies on your domain to a victim's browser and tries to reuse a token generated for a different user.

Anti-forgery token is not reused

As I read the anti-forgery system that ASP.NET MVC implements generate a token that can be reused across the same session, my question is why then this token changes every time I generate a new form in my app? I am talking about the hidden input field, not about the cookie value.
Thanks.
No. the token is not reused.
Every page refresh will generate a new value in Form input (and Cookie as well, in case it is invalid or not exist). upon submission, the server will try to match the form value against the Cookie value.
Taken from Professional ASP.NET.MVC 3 book
Token Verifi cation ASP.NET MVC includes a nice way of preventing CSRF
attacks, and it works on the principle of verifying that the user who
submitted the data to your site did so willingly. The simplest way to
do this is to embed a hidden input into each form request that
contains a unique value. You can do this with the HTML Helpers by
including this in every form:
<form action=”/account/register”
> method=”post”> <#Html.AntiForgeryToken()> … </form>
Html.AntiForgeryToken will output an encrypted value as a hidden
input: This value
will match another value that is stored as a session cookie in the
user’s browser. When the form is posted, these values will be matched
using an ActionFilter:
[ValidateAntiforgeryToken] public ActionResult
> Register(…)

ASP.NET MVC 3 binding making sure form values take priority

With a POST request in case it has the same parameter in the query string and in the body of the request which one takes priority with model binding?
From this article, in the "Value Provders" section.
Previously bound action parameters, when the action is a child action
Form fields (Request.Form)
The property values in the JSON Request body (Request.InputStream), but only when the request is an AJAX request
Route data (RouteData.Values)
Querystring parameters (Request.QueryString)
Posted files (Request.Files)
So if the same name appears in multiple places, the last place the model binder looks will take precedence (I think), in your case, the querystring.
Easiest thing to do is try it. Enter a url with a &id=23" and make sure you have a HTML input field named "id" and POST that back to the controller and see which one is passed.

How to pass id value to controller instead from query string while getting details of page in MVC

I want to pass insured id to controller while getting insured details which looks like:
// GET: /Insured/Details/123456789
But I don't want to pass this id number 123456789 in query string for security reasons.
Can somebody suggest me the best way. I am new to MVC.
Thanks
Try submitting the value as a hidden parameter via POST. You'll need to use a form to do POST submits though. You can't use links.
<form method="POST" action="/Insured/Details">
<input type="hidden" name="insuredid" value="123456789"/>
<input type="submit"/>
</form>
You would then get the value via request parameter. If using Java servlets, it would look something like this:
String myInsuredId = request.getParameter("insuredid");
I imagine it would look similar to other platforms as well.
NOTE: Although passing values as hidden parameters hides the data from view, this does not prevent people from sniffing the submitted data or checking the HTML source of your page. If you really want to make this secure, you'll need to use some form of encryption/security. Try looking into HTTPS posts.
You need to sanitize your input in the controller, for example if the customer is logged in you could check that the ID passed to the controller truly belongs to the customer.
Anything that is passable in request (whether it's POST or GET) is spoofable.
You should also look into serving the page over HTTPS.
E.g. (asp.net MVC / C#)
public ActionResult Details(string id)
{
if (Check(id) == false)
{
// Handle invalid input
throw new HttpException(404, "HTTP/1.1 404 Not Found");
}
// create the model
...
}

in MVC, how to verify reliability of submitted form hidden fields?

In mvc, when submitted to a controller, how can I verify that a user hasn't maliciously changed readonly hidden form fields?
When displaying the form fields render a hidden field that contains a hash for the displayed values.
When receiving the post request hash the received data again and compare this hash to the value of the hidden field.
Two options I can think of:
Encrypt the fields when displaying them, then decrypt server side and use the value
Don't store sensitive information in hidden fields and instead store them in the session (recommended)

Resources