ViewModel data being passed in address bar - asp.net-mvc

I have my change password controler.
The user changes the password and clicks submit.
I have my viewmodel of person p.
I am not passing it at all to my success page.
return View("succsessFulLogin");
And still I am getting
http://localhost:50010/Password/ChangePassword?AccountName=username&CurrentPassword=currentPassValue&NewPassword=newPassValue&NewPasswordCheck=newCheckPassValue
In the address bar
this is my code on the page:
#using (Html.BeginForm("ChangePassword", "Password", FormMethod.Get))
{
#Html.HiddenFor(model => model.AccountName)
<br />
<div>
<h4>#Html.LabelFor(m => m.CurrentPassword)</h4> #Html.PasswordFor(m => m.CurrentPassword, new { onkeydown = "capLock(event);" } ) #Html.ValidationMessageFor(m => m.CurrentPassword)
</div>
<br />
<div>
<h4>#Html.LabelFor(m => m.NewPassword)</h4> #Html.PasswordFor(m => m.NewPassword, new { onkeydown = "capLock(event);" }) #Html.ValidationMessageFor(m => m.NewPassword)
</div>
<br />
<div>
<h4>#Html.LabelFor(m => m.NewPasswordCheck)</h4> #Html.PasswordFor(m => m.NewPasswordCheck, new { onkeydown = "capLock(event);" }) #Html.ValidationMessageFor(m => m.NewPasswordCheck)
</div>
<br />
<p>
<button class="btn-lg" type="submit">#Global.SAVE</button>
</p>
}

I disagree with osman Rahimi.
Using HTTP POST is in no way more secure than HTTP GET! As long as you're passing everything as clear text over http, you can read anything passed to and from the server, even if it isn't shown in the address bar. If you want to check me yourself, all you have to do is download fiddler, check the request and responses your page generates and see for yourself.
The proper way to transmit passwords on the net is to make sure you're using SSL and hashing the passwords. I am by no means an expert on the subject, but I think you'll find need in these answers:
Securely Transfer User Entered Password
How should password be transfered for logon in Asp.net Identity
How to securely save and send login username/password?

when you are using HTTP GET the browser send data in URl and in this way you have limitation up to 2048 characters.
know more about HTTPGET and HTTPPOST
to keep your data secure and protected change your method To POST Like this :
#using (Html.BeginForm("ChangePassword", "Password" FormMethod.Post, null))
{}
then Add [HTTpPost] to your Action Method in your controller , like :
[HttpPost]
public ActionResult ChangePassword(yourmodel model){}

Related

asp.net core mvc application form post with query string parameters

I am building a login form in .net core mvc. Below is my login form
<form class="c-form" asp-controller="Account"
asp-action="Login">
<div class="form-group">
#Html.TextBoxFor(m => m.Username, new { #class = "form-control c-input", placeholder = "Username" })
</div>
<div class="form-group">
#Html.PasswordFor(m => m.Password, new { #class = "form-control c-input", placeholder = "Password" })
</div>
<div class="help-text help-text-error">
#Html.ValidationMessage("UserNamePasswordInvalid")
</div>
<div class="">
<button type="submit" class="btn-c btn-teal login-btn width100">Login</button>
</div>
If a form is posted with incorrect credentials user stays on the page with validation failure messages.
Login page also has return url in query string, when the form is posted query string parameters are lost. What is the correct way of doing form post in .net core.
To keep the query string when the form is submitted write a hidden field in the form containing the query string contents:
#Html.Hidden("returnUrl",#Request.QueryString)
Make sure your controller action that handles the post request has a parameter called returnUrl (or the model that is passed as a parameter has that property) and the model binding will take care of passing it through to the controller. Then in the controller action if the login is successful use that data to redirect accordingly.
I know that it's passed a lot of time, but I found a better solution for this problem.
I added a parameter called QueryString in Model as Dictionary string
in view, in tag form, add
So at this time, the post have the parameters in query string<form asp-all-route-data="#Model.QueryString"
Your controller/PageModel method must contain all parameters that you need to persist. Something like this:
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
If the controller and action pair for getting and posting the form is the same, than it is simpler to just delete asp-controller and asp-action attributes from the form opening tag, leaving your like this:
<form class="c-form" method="post">

Placing MVC 4 login control on Home/index page

First off I am new to MVC, I was a webforms guy...
I want to show my login control on my home/index page, but no matter what I do I run in to errors. I have tried various techniques and have gotten many errors with each technique, so I wont list them all here.
Right now I have it set that if Request.IsAuthenticated then show the username else show the login form. But the form is obviously looking at the home controller and nothing happens when I submit the login.
Any advice would be much appreciated. I have been dabbling for days on this.
Thanks :)
Here is the Code:
'#{
ViewBag.Title = "MyApp";
}
<p>Code for main Index Page here</p>
#model Application.Models.LoginModel
#{
ViewBag.Title = "Log in";
}
#if (Request.IsAuthenticated) {
<text>
Hello, #Html.ActionLink(User.Identity.Name, "Manage", "Account", routeValues: null, htmlAttributes: new { #class = "username", title = "Manage" })!
#using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm" })) {
#Html.AntiForgeryToken()
Log off
}
</text>
} else {
<section id="loginForm">
<h2>Use a local account to log in.</h2>
#using (Html.BeginForm(new { ReturnUrl = "RedirectToAction" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Log in Form</legend>
<ol>
<li>
#Html.LabelFor(m => m.UserName)
#Html.TextBoxFor(m => m.UserName)
#Html.ValidationMessageFor(m => m.UserName)
</li>
<li>
#Html.LabelFor(m => m.Password)
#Html.PasswordFor(m => m.Password)
#Html.ValidationMessageFor(m => m.Password)
</li>
<li>
#Html.CheckBoxFor(m => m.RememberMe)
#Html.LabelFor(m => m.RememberMe, new { #class = "checkbox" })
</li>
</ol>
<input type="submit" value="Log in" />
</fieldset>
<p>
#Html.ActionLink("Register", "Register", "Account") if you don't have an account.
</p>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
</section>
}
'
you have to modify your form like this:
#using (Html.BeginForm("Login","Account",FormMethod.Post, new { ReturnUrl = ViewBag.ReturnUrl }))
the key is the "Login","Account" part, that tells the form to post the data to the login action of the account controller instead of the home controller. I fought with the same thing for a few hours then figured it out.
if the data does not post to the account controller (the controller that actually validates the username and password and logs the user in) it will never try to log them in.
reason is :
by default in the routeconfig.cs class sends any links or forms that do not specify an action and controller send all stuff to the Index action of the Home controller.
Hope this helps
You should use a Child Action:
In your controller:
[ChildActionOnly]
public ActionResult LoginForm()
{
return View("_LoginFormPartialViewHere");
}
Then in your homepage view:
#{ Html.RenderAction("LoginForm"); }
In your partial view for your login form, you can strongly-type the view for your login view model, but make sure to specify a different post action for your form than the default "postback" model. This action will handle the login and only the login (so not your homepage action).
Your problem here is that you are attempting to write code without actually understanding what it does. Without understanding what it does, you are simply left randomly changing things hoping to find something that works. This is a very poor way to write software.
Your problem is rooted in the fact that you don't understand that MVC is merely generating HTML, and without understanding what that HTML is supposed to be doing, you have little hope of randomly figuring this out.
First, MVC has no concept of a "login control". They're just HTML form fields, and they sit within an HTML form element. Those form fields are posted to your controller using standard HTML, which means you have to ensure your form action method is correct, and that the action url is correct.
Secondly, when those form fields are posted, you have to have an action method that will receive the post. If that action method is not the same as the action method used in the GET, then you will have to tell the BeginForm() helper where to post to.
In MVC, you can't think like Webforms and just assume everything gets done for you. You have to do everything yourself, and make sure every link, every action, every selector, every bit of javascript, etc.. is all correct. This is more work than WebForms, but it's also more powerful and more efficient.

Disable Required Validation Specific Field in the View ASP.NET MVC 4

if someone could give me some hint I would appreciate.
I'm searching for a while, and I even found a post I thought it would solve my problem, but it didn't.
Disable Required validation attribute under certain circumstances
Basically I have a simple User.cs model where I have username, FirstName, LastName and SignupDate
All have the required annotation and I would like to solve this without erasing the Required tag.
After I generate the view, I erase in the view the html code for the SignupDate:
<div class="editor-label">
#Html.LabelFor(model => model.SignupDate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.SignupDate)
#Html.ValidationMessageFor(model => model.SignupDate)
</div>
When I click submit it does not work.
Also if I do the suggested in the other post
<div class="editor-label">
#Html.LabelFor(model => model.SignupDate)
</div>
<div class="editor-field">
#Html.TexBoxFor(model => model.SignupDate, new { data_val = false })
</div>
If I leave it as blank also does not work..
Any suggestions? Thanks!!
You can disable client validations on the view and remove the errors on the modelstate for those entities you don't want to validate the value.
In my case I wanted to change a Password only if the user typed one. Using Html.HiddenFor was not a good approach due to sends the password to the client every time, and password shouldn't be sent.
What I did was to disable the client validations on the view
#model MyProject.Models.ExistingModelWithRequiredFields
#{
ViewBag.Title = "Edit";
Html.EnableClientValidation(false);
}
That allows me to submit the form even with empty values. Please note that all client validations are ignored, however server validations still run, so you need to clear those you don't need to be executed. In order to do this, go to the action in the controller and remove the errors for each property you need to
public ActionResult Edit(ExistingModelWithRequiredFields updatedModel)
{
var valueToClean = ModelState["RequiredPropertyName"];
valueToClean.Errors.Clear();
if(ModelState.IsValid)
{
...
//Optionally you could run validations again
if(TryValidateModel(updatedModel)
{
...
}
...
}
...
}
I think this should solve it, assuming model.SignupDate holds a value:
<%: Html.HiddenFor(model => model.SignupDate) %>

Will Using AntiForgeryToken sufficient to cover the authorization rule in a POST action method

Will Using AntiForgeryToken covers the authorization rule in a POST action method
I have the following Create.cshtml view for creating a new Order:-
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<fieldset>
<legend>Create New Order</legend>
<ol>
<li>
#Html.LabelFor(m => m.OrderName)
#Html.TextBoxFor(m => m.OrderName)
</li>
<li>
#Html.LabelFor(m => m.OrderType)
#Html.TextBoxFor (m => m. OrderType)
</li>
<li>
#Html.LabelFor(m => m.OrderDate)
#Html.TextBoxFor(m => m. OrderDate)
</li>
</ol>
<input type="submit" value="Create" />
</fieldset>
}
The above view will be rendered when calling the following GET action method:-
[Authorize (Roles="customerservice")]
public ActionResult Create()
{
return View("Create");
}
and the POST action method is:-
//
// POST: /Create
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize (Roles="customerservice")]
public ActionResult Create(Order r)
{
// Code goes here
return View(model);
}
Now my question is as follow:-
since i am using the Antiforgery token in my view , then i will guarantee that any valid call to the "POST:/ Create" is done; from the application itself + when the user is inside the Create view, which means that the user is under the customerservice Role.
So does this means that if i remove the authorized attribute from the POST Create action method, then i am still secure? since if the application receive a "POST: Create" request then this means that the user is already authorized from the "Get: /Create" action method and that the request was sent from the Create view?
Any comment about the above question.
Best Regards
AntiForgeryToken consist from three items:
Attribute for action
Helper method in view
Cookie
AntiForgeryToken is not unique per each request, so if user is not logged, this is potentially risk.

MVC4 Razor Looses UserID if Unbound

I'm creating some user profile edit forms in MVC4 at the moment and for testing I was rendering the UserId property into a readonly textbox on the form like this:
<li>
#Html.LabelFor(model => model.UserId)
#Html.TextBoxFor(model => model.UserId, new { #readonly="readonly"})
</li>
As I'm nearing completion of the edit form I removed this textbox as it's just using up real estate. Once I had done this the model sent back to the controller when saving had the integer default value of 0 and then the Entity Framework blows up as it cannot update any rows. So I added this to the form:
<li>
#Html.HiddenFor(model => model.UserId, new { #readonly="readonly"})
</li>
Is this a safe move? Should I be using the ViewBag for things like this? On the profile details page I render an edit button like this:
#Html.ActionLink("Edit", "Edit", new { id=Model.UserId })
Meaning that the UserId is rendered in the link. Is this safe and secure or do I need to rethink how I move the models and ids around the UI?
TIA,
Is this a safe move?
This will do the job of sending the id to the server. Just get rid of the readonly="readonly" attribute which makes very little sense for a hidden input.
Should I be using the ViewBag for things like this?
This doesn't change anything in terms of security. Any user could still put whatever id he wants. Whether you are using a hidden field or an ActionLink you are still sending the id as plain text to the server and anyone could forge a request and put whatever id he wants. So if you site uses some form of authentication you must absolutely check on the server side that the id that you received actually is a resource that belongs to the currently authenticated user before attempting to perform any actions on it. Otherwise some authenticated user could supply the id of a resource that belongs to another user and be able to update it. Of course that's just a hypothetical scenario, it's not clear at all if this is your case and whether this id needs to be secured.
If UserId is sensitive, then there are other options
Keep UserId server side only with Session state (if your architecture allows for Session)
Put it in an encrypted cookie. Note as per Darin, that these can be compromised.
If it isn't sensitive, then your HiddenFor is fine - post it back with the rest of the form.
Don't put it in your ActionLink Querystring unless this is part of your route (i.e. /Controller/Action/id)
I would strongly suggest using ValueInjecter. Here is a code snippet doing the same thing
[HttpGet]
public new ActionResult Profile()
{
var model = new ProfileModel();
model.InjectFrom<UnflatLoopValueInjection>(this.GetCurrentUser());
return View(model);
}
[HttpPost]
public new ActionResult Profile(ProfileModel model)
{
if (ModelState.IsValid)
{
this.GetCurrentUser().InjectFrom<UnflatLoopValueInjection>(model);
try
{
_userService.SaveOrUpdate(this.GetCurrentUser());
TempData["Success"] = "User was successfully updated.";
return RedirectToAction("Profile");
}
catch (Exception)
{
ModelState.AddModelError("Exception", "Unexpected error");
}
}
return View(model);
}
And here is the view...
#using (Html.BeginForm("Profile", "Account", FormMethod.Post, new { #class = "form-horizontal" }))
{
#Html.ValidationSummary(true, "Unable to update profile. Please correct the errors and try again.", new { #class = "alert alert-block alert-error" })
#Html.EditorForModel()
<div class="form-actions">
<input type="submit" value="Update" class="btn btn-primary" />
</div>
}

Resources