AntiForgeryToken deprecated in ASP.Net MVC 4 RC - asp.net-mvc

I just installed ASP.Net MVC 4 RC to replace ASP.Net MVC 4 beta. When trying to run an existing application I'm getting an error message that AntiForgeryToken has been deprecated. Here's my code:
using (Html.BeginForm("", "", FormMethod.Post, new { id = "MonthElectionForm" }))
{
#Html.AntiForgeryToken("AddEditMonthElection")
}
---- UPDATE ---
ASP.Net MVC 4 RC has made the Salt property obsolete for ValidateAntiForgeryToken attribute and AntiForgeryToken html helper. So, now my code looks like this:
controller:
[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult CreateCompany(CompanyDataEntryViewModel modelData)
{...}
form:
#using (Html.BeginForm("", "", FormMethod.Post, new { id = "CreateCompanyDataEntryForm" }))
{
#Html.AntiForgeryToken()
...
}
Looking at generated HTML, AntiForgeryToken still generates a hidden field and provides an encrypted value. My action still works too. But I've lost the ability to designate a key to use in the encryption process. I'm not too sure how the process works, but before I can tell I was setting the salt value on the action and on the form. The values had to match in order for the action to accept the post. So, how do you set the salt value now? I think it has something to do with AntiForgeryConfig AdditionalDataProvider but I cannot find anything googling on how to use AntiForgeryConfig AdditionalDataProvider. Please help.
Thanks

Setting the salt parameter is unnecessary and didn't provide any additional protection, so we removed support for it.
Please see my response at How to choose a salt value for ValidateAntiForgeryToken for more information.

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.NET how to secure submitting forms after edit

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();
}

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

ASP .NET MVC How to make Url that look like POST not GET

So normally I have links like:
http://domain.com/action?some=1&foo=2
and so on.
It's make me really upset, as some clever users might just reinvent link on their own and get access to some data, which is not desirable. I know i can setup security On server side, but i'd like to make links look like:
http://domain.com/action
And 'some' and 'foo' send like POST request
Actions in ASP.NET MVC don't distinguish betweed Post and Get as far as the parameters to the actions are concerned. However, you can start by marking your actions with the attribute [HttpPost]. This will limit the request options to post only.
Now to the second "issue", you need to change all your links so that you use post instead of get, you can do this by using ajax, check out $.post in jQuery for that.
This doesn't solve any security issues with your parameters though, it generally doesn't matter if you show it in the querystring or of it is sent by a post. If someone wants to inject something into your post-data, it's not rocket science.
You have to wrap it in a form for it to work; with the inputs being hidden. On the server side you have to restrict the action to only responding to a POST request. However, this doesn't really solve your problem as a sufficiently interested and knowledgeable user can just as easily craft a POST as a GET.
You can add form to the view and apply [HttpPost] attribute for the action which will take the model after the post.
Adding form to the razor view (also you will need a button or a link to sumbit):
#using (Html.BeginForm("SomeAction", "SomeController", FormMethod.Post, new { #id = "someFormId" }))
{
#Html.HiddenFor(model => model.some)
#Html.HiddenFor(model => model.foo)
}
And here is a Controller with action to proccess your post:
public class SomeController : Controller
{
[HttpPost]
public ActionResult SomeAction(SomeModel model)
{
//process 'some' and 'foo' here
return View(model);
}
}
To enhance security you can easily encrypt/decrypt "some" and "foo" values.

ASP.NET MVC Login ReturnUrl always NULL?

Using Forms Authentication in ASP.NET MVC when trying to log back into a site, it puts a ReturnUrl parameter in the query string. My Logon action method accepts a "returnUrl" string. However it seems that returnUrl string is always null, even when it is clearly in the query string. Any thoughts on why this might be the case or a possible fix?
This tends to happen when you're using one generic logon form, but you're explicitly specifying the Controller and ActionMethod (which is causing a form post, but losing the querystring)
Just to clarify, this is what your code should look like in your BeginForm:
Html.BeginForm("LogOn", "Account", new { ReturnUrl = Request.QueryString["ReturnUrl"] })
EDIT: This is by design as RickAnd mentions in comments below. However it doesn't allow for the UI pattern of being deep in a site, clicking on LogOn, then returning to the page you were previously on, if it allows anonymous users. It's a commonly requested pattern. David Allen's approach to LogOff would also work nicely for a clean redirect at LogOn.
Maybe you don't include the ReturnURL parameter into you login form's action attribute, thus posting to a URL without that parameter?
Basically, The Asp.net MVC has some hidden features. For Example when you pass variable 'id' to controller action, it interprets 'id' as default identifier and puts it on browser query with fore slash.By using another name instead of 'id' we will see '?' rather than fore slash. Because of setting the 'id' name on RegisterRoutes method on global.asax file.
In this Problem you have created a custom data passer to controller by using this code:
using(Html.BeginForm("LogOn", "Account", FormMethod.Post))
{
//form fields
}
So Asp.net MVC ignores other useful data to pass to controller action, and we'll see returnUrl always null.
While, by using this, Asp.net MVC acts Correctly and returnUrl is mounted:
using(Html.BeginForm())
{
//form fields in LogOn View
}
By the way, When we use custom data passer to controller action, must pass another data manually like this:
using(Html.BeginForm("LogOn", "Account", new {ReturnUrl = Request.QueryString["ReturnUrl"] }))
{
//form fields
}
There are two ways I can think of to deal with logon and logoff scenarios.
Dave Beer outlined one way, above.
There is another approach that works in many situations. I used it when I coded the NerdDinner tutorial. The tutorial provides us with a logoff function that logs you off and takes you home. I did not want that. I wanted to return to the page I was on before I logged off. So I modified my Account controller logoff action to look like this
public ActionResult LogOff()
{
FormsService.SignOut();
return Redirect(Request.UrlReferrer.ToString());
}
You can get fancier and pass in a returnUrl and test for it, in case you want to override this behavior. But I don't need that. This achieves the desired result. The Logon can work similarly. Maybe there are ways to use the MVC framework to do this for me, but until I learn them, this is VERY simple and works reliably.
Try the following:
public static MvcForm BeginForm(this HtmlHelper htmlHelper, string id)
{
string formAction = htmlHelper.ViewContext.HttpContext.Request.RawUrl;
TagBuilder tagBuilder = new TagBuilder("form");
tagBuilder.MergeAttribute("id", id);
tagBuilder.MergeAttribute("action", formAction);
tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(FormMethod.Post), true);
HttpResponseBase httpResponse = htmlHelper.ViewContext.HttpContext.Response;
httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));
return new MvcForm(htmlHelper.ViewContext.HttpContext.Response);
}
First ensure you have set the login url in the web.config, Next, ensure your Signin Form does not contain anything like action, for example:
View:
If you specify action you will always get null for return url:
Controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SignIn(string userName, string password, bool? rememberMe, string returnUrl)
{
}

Resources