MVC.NET how to secure submitting forms after edit - asp.net-mvc

When I want to submit a form to save an edited record, I should pass its Id to controller. Then a client (or attacker) may change some information (e.g. this Id) on the form that I don't want to be changed. I can create a hashed hidden field to check that read-only fields have not been changed and verify it when it is posted to controller.
Is there any other good practice for this issue?
Thanks

You can encode data you want to protect with server side algorithm, that way that view receives encoded data only. When user passed the form to controller you decode data and check for validity. Also remember to implement not only client side validation, but also server side validation for your model.

AntiForgeryToken: A great feature in ASP.NET MVC is the AntiForgeryToken. This Generates a hidden form field (anti-forgery token) that is validated when the form is submitted. The anti-forgery token can be used to help protect your application against cross-site request forgery
.cshtml Code
#using (Html.BeginForm("Index", "Home"))
{
#Html.AntiForgeryToken()
}
Controller Code
[ValidateAntiForgeryToken()]
[HttpPost]
public ActionResult Index()
{
//Your Code
return View();
}

Related

ValidateAntiForgeryToken doesn't do the only thing it is suppose to do

I am implementing AntiForgeryToken feature to my asp.net core mvc project. As usual, I have included #Html.AntiForgeryToken() inside the form tags so it looks like this:
<form method="post" action="mycontroller/myaction">
#Html.AntiForgeryToken()
<input type="text" name="myInput"/>
<button type="submit">Submit</button>
</form>
and as you can imagine, here is the myaction action in my mycontroller controller:
[HttpPost]
[Route("somepath")]
[ValidateAntiForgeryToken]
public IActionResult myaction()
{
//some code here
}
Now the problem is, I NEVER GET ANY ERROR!!
I removed the #Html.AntiForgeryToken from the view and the [ValidateAntiForgeryToken] doesn't do a thing! the post action works just fine.
Here are two things I have tried that might give you a clue:
I tried both [ValidateAntiForgeryToken] and [ValidateAntiForgeryToken()], no difference!
Someone said that the attribute only works in authorized controllers or actions. Tried this in my controller that has the [Authorize] tag.
PS: I have not added any code in my Startup.cs like services.AddMvc(...). Could it be something about that??
Please help.
ValidateAntiForgeryToken is used to prevent cross-site request forgery attacks.
Antiforgery middleware has been added to the Dependency injection container when services.AddMvc() is called,and The FormTagHelper has injected antiforgery tokens into HTML form elements already.You don't need to call #Html.AntiForgeryToken()
For more details ,you could check this document.
In and MVC app (which you have there), request verification using an anti forgery token is opt in. You opt in by decorating the controller action with the [ValidateAntiForgeryToken] attribute. If you omit the attribute, the request is not subject to verification. In each of the scenarios you described, there is no reason for an error. The only time you are likely to see an error (in the shape of a 400 HTTP status code) in an MVC app is if you decorate the action with the [ValidateAntiForgeryToken] attribute but the cookie or token are not included as part of the request payload.
In Razor Pages, all POST requests are verified by default. You can opt out of request verification, in which case you can opt in on a page by page basis by adding the attribute to the PageModel class (not the handler method) The anti-forgery token is generated by the form tag helper when the method is set to POST in both Razor Pages and MVC views.
Sometimes, you might want to post without a form (using AJAX most commonly) in which case you need to generate the anti-forgery token in the view so that you can include it within the post request payload. The Html.AntiforgeryToken helper (which is a legacy from older versions of MVC) provides a convenient way to do that.
I've written in detail about this process here: https://www.learnrazorpages.com/security/request-verification

MVC - View without model but has one field

I have a page which will require a password field only. User has to enter his password then submit. Is it possible to create a view for that without a model? I asked because if I need to create a model then it will have a password property only. I hope there is a simple way for this simple page.
If you don't want to create View Model then it is completely fine. You can loose some benefit like automatic client side validation ( data annotation). It means you have to do all validation by your self in client side and later on server side.
This is simple way you can do that.
Your controller code something look like this.
public ActionResult AcceptPasswordOnly(string Password)
{
// Do your validation if want password back to field if validation failed then set in ViewData["Password"] = Password
return View();
}
Your view code something look like this.
#using (Html.BeginForm("AcceptPasswordOnly", "Home"))
{
<div>Enter Passowrd :</div> #Html.TextBox("Password" , ViewData["Password"] ?? "")
<input type="submit" />
}
Note: Just remember that #Html.TextBox first argument is name and controller method parameter must same so you can access directly.
This way you can do directly without creating model and just using primitive datatype.

Does MVC remember checkbox values after submit?

I'm a php head and getting to grips with ASP.NET MVC 5.
In php, after submitting checkbox fields, in order to post back the form with the checkboxes you checked initially set to true, you have to run a if isset on em.
However reading up on model binding in mvc, it seems that this is done automatically for you, i.e checkboxes are returned after form submit checked, if originally selected, using either the HTML.CheckBox or HTML.CheckBoxFor helpers.
Is this the case, or am I expecting too much of MVC?
No, ASP.NET MVC doesn't remember checkbox values after they're submitted. Being an HTTP application as soon as ASP.NET MVC has rendered the HTML it ends the request and forgets everything about what it's just done. Then upon submitting a form ASP.NET MVC processes the incoming HTTP request and maps it to your model via its model binding (more on how it does this in a moment).
Having come from a PHP background myself this is one of those questions I always had when starting with ASP.NET MVC.
With ASP.NET MVC you have to remember that you're working within the context of a complete framework, and in order to ensure you're as productive as possible ASP.NET MVC will take care of a lot of the mundane work for you - ASP.NET MVC's model binding is a perfect example of this.
When submitting a form, the ASP.NET MVC framework will parse all incoming post data and attempt to automatically map it to the values you're providing it via your controller action.
So where as in PHP you'd normally do something along the lines of:
if(isset($_POST['checkboxValue'])) {
$checkboxVal = $_POST['checkboxValue'];
}
ASP.NET MVC will automaltically bind the incoming post data to your action parameter like so:
[HttpPost]
public ActionResult Submit(bool checkboxValue){
}
It does this by checking the parameter name (checkboxValue) matches that of the post data array key, and that the type also matches up. For instance, if you were to change the above checkboxValue from a boolean to a string and change the name, then ASP.NET MVC's model binding will be unable to match the property to the post data and will not automatically set the value for you.
It's also worth noting that ASP.NET MVC's model binding doesn't know how you created the checkbox.
The HTML.CheckBox and HTML.CheckBoxFor html helpers are purely a means to make it easier for you to create the HTML. If you were to manually write the HTML yourself then the model binder will still successfully bind the submitted data.
Edit:
As #DrinkBird has quite rightly pointed out, you're also able to access all of your form's post data by using the FormCollection instance like so:
[HttpPost]
public ActionResult Submit(FormCollection postData){
}
This collection represents all of the data posted to the Submit action.
Yes, model-binding should allow you to retrieve the value of a checkbox on submission.
if your model looks like:
public class myModel
{
public bool myBool {get; set;}
}
and in your HTML, you've used the helper
#Html.CheckBoxFor(m => m.myBool)
Then in your post action to handle the submission:
[HttpPost]
public ActionResult MyAction(myModel model)
{
var whatsThis = model.myBool;
}
...whatsThis will be true if the checkbox was checked, false if not.
Part of why this works is that when you use #html.CheckBoxFor, it also places a hidden form field that will pass false if the box is unchecked, to aid with model binding -- if it didn't, per HTTP there would be no varibalbe 'myBool' submitted in the post-vars collection.
If you return this model back into the form (say, if it didn't validate), then the form will re-present the checkbox in whatever state it was in on submission:
[HttpPost]
public ActionResult MyAction(myModel model)
{
if(!ModelState.IsValid)
{
return View(model);
}
else
{
//do success
}
}

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
...
}

Post Redirect Get in ASP.NET MVC And Validation With Restful URLs

I have a restful URL for the action of editing a page. This is implemented on the controller as an Edit method, which accepts GET requests and an Edit method that accepts POST requests.
This means you can visit the Edit URL and it will display a form for a GET or save a form for a POST.
[HttpGet]
public ActionResult Edit(int id) {
...
}
[HttpPost]
public ActionResult Edit(EditModel model) {
...
}
The Post-Redirect-Get (PRG) pattern seems pretty black and white, because it essentially redirects every POST back to a GET action. However, I need to be convinced that this is the correct thing to do.
My plan is that in the POST action, if the model is valid I will use the Post-Redirect-Get pattern to send the user to a reasonable location (probably the Index or Details action).
However, if there is a model validation problem, I still want to just display the view. I don't want to redirect the user, because it means stuffing the model and ModelState into temporary data and redirecting to the GET action - and then adding logic into the GET action to handle the temp data. I could avoid all of this by simply displaying the view.
Yes, if the user presses F5 it will re-submit the form and they will be presented with the "resubmission warning", but then the same page (asking them to fix validation errors). However, it seems unlikely that they will hit F5 and there is also no danger of a double-submission as the form will simply fail the validation once again.
If the validation passes, the user will be redirected and they will be safe from double submissions.
So should I implement additional code and stuff data into temp data in order to strictly follow the PRG pattern, or is it more sensible to use the PRG pattern when the form is valid and data is being stored?
You should only do the redirect if the form information is valid; in the case of submission errors, return the view from the same Edit method.
Doing it this way is compliant with PRG, because if your model is invalid, you are not allowing any changes to be made to the state of objects on the server. PRG is designed primarily to prevent multiple posts that can change the state of server objects (e.g., business objects, database tables, etc.) in unpredictable ways; in your validation example, however, the user can hit resubmit as many times as they want and they will always be sent back to the initial view with validation errors--nothing on the server changes. Therefore, you have it right: only issue the Redirect if your model passes validation in your presentation tier.
Even though Ken's answer does highlight an important fact - PRG doesn't necessarily mean "blindly return a redirect when posting" - you still might want to do redirect and preserve modelstate sometimes.
The easiest way to handle that scenario, is using action filters to export modelstate to the session (before redirecting), and then import modelstate (before executing the new action). Kazi Manzur Rashid has a couple of excellent blog posts (Part 1 Part 2) on best practices in ASP.NET MVC. They're quite old, but many of the tips there are still very much applicable. Tip number 13 in the first article is exactly what you're looking for.
PRG is the right thing to do.
You do a POST to the action and if modelstate is invalid, you just 'export' your modelstate data into a variable and redirect to the get action.
This has the benefit as opposed to the accepted answer that you don't need to rewrite code on the [Post] action to recreate the view.
on the get action you load the ModelState exported from the post one.
TempData is an excellent place to do this stuff, code will be something like this:
[HttpGet]
public ActionResult Edit(int id) {
// import model state from tempdata
...
}
[HttpPost]
public ActionResult Edit(EditModel model) {
// if modelstate is invalid
// save modelstate in tempdata
// redirect to Edit/{id}
// else
...
RedirectToAction("List")
}
this can be automated using AttributeFilters, there an excellent post create by #ben-foster here:
Automatic Validation of Modelstate

Resources