Securely Show and post a Form - asp.net-mvc

suppose you show a form using beginform
<div class="col-md-6">
<div class="form-group">
#Html.LabelFor(m => m.IsLock, new { #Class = "col-md-12 control-label" })
<div class="col-md-12">
#using (Html.BeginForm("ChangeLockUser", "UserAdmin", new { area = "Admin", id = Model.UserId }, FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.Hidden("returnUrl", Url.Action("Details", "UserAdmin", new { Area = "Admin", id = Model.UserId }))
<div class="input-group mb-3">
#Html.TextBox("LockStatus", Model.IsLock ? "غیر فعال" : "فعال", new { #class = "col-md-12 form-control", #readonly = "readonly" })
<div class="input-group-append">
<button type="submit" class="btn btn-outline-secondary">#(Model.IsLock ? "فعال شود" : "غیرفعال شود")</button>
</div>
</div>
}
</div>
</div>
before submitting I can easily change the Id in the post address so the form will manipulate another record!!!
is there any method to solve this security problem?
thank you

Don't use UserId in front-end, you can get the current logged in user in the Controller inside ActionResult like
using Microsoft.AspNet.Identity;
string currentUserId = User.Identity.GetUserId();
Get the UserId after submitting then use it.

Related

Model Data not binding to textboxfor after insertion in MVC

I'm facing a problem in mvc 4, i have create action method where i insert the data in db and then return model to View but the model data not bind to hidden Field like Id and Voucher number,
in other fields data binds properly but the issue is with these Id and VoucherNum, Id is primary key and VoucherNum is Unique.
I have mentioned the code and html.
Code:
[HttpPost]
public ActionResult Create(Payment payment)
{
payment.VoucherNum = db.Payments.Count() + 1;
Ledger ledger = new Ledger();
ledger.CusId = payment.CustomerId;
ledger.Date = payment.Date;
ledger.Remarks = payment.Remarks;
ledger.Type = payment.Type;
string negativeAmount;
negativeAmount = "-" + payment.Amount;
ledger.Amount = Convert.ToInt32(negativeAmount);
ledger.IsActive = true;
payment.IsActive = true;
db.Payments.Add(payment);
db.Ledgers.Add(ledger);
db.SaveChanges();
ViewBag.CustomerId = new SelectList(db.Customers.ToList()
.Select(x => new { Id = x.Id, CustomerCode = x.Name + "-" + x.CustomerCode }
), "Id", "CustomerCode", payment.CustomerId);
var model = db.Payments.Find(payment.Id);
return View(model);
}
<h2>Payments</h2>
<hr />
<div class="row">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="col-md-4">
<div class="form-group">
<label class="control-label">Vocher#</label>
#Html.TextBoxFor(model => model.VoucherNum, new { #class = "form-control", #readonly="true"})
#Html.HiddenFor(model=>model.Id)
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="control-label">Customer</label>
#Html.DropDownList("CustomerId", (IEnumerable<SelectListItem>)ViewBag.CusId, "--Select Customer--", new { #class = "form-control" })
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="control-label">Date</label>
#Html.TextBoxFor(model => model.Date, new { #class = "form-control", #id = "date"})
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="control-label">Amount</label>
#Html.TextBoxFor(model => model.Amount, new { #class = "form-control" })
</div>
<div class="form-group">
<label class="control-label">Type</label>
#Html.TextBoxFor(model => model.Type, new { #class = "form-control" })
</div>
</div>
<div class="col-md-8">
<div class="form-group">
<label class="control-label">Remarks</label>
#Html.TextAreaFor(model => model.Remarks, new { #class = "form-control", #rows = "5" })
</div>
<input type="submit" value="Payment Receive" class="btn btn-primary pull-right" />
</div>
}
</div>
Because the helper method will look in to the model state dictionary first to populate the value of the input. The model state dictionary currently has null value for the VoucherNum before you saved it, and the helper method will use this value to generate the value of the input field.
To fix this, you can explicitly clear the model state dictionary before returning to the view,
db.Payments.Add(payment);
db.SaveChanges();
ModelState.Clear();
var p = db.Payments.Find(model.Id);
return View(p);
Or even better, follow the PRG pattern. With the Post-Redirect-Get pattern, After successfully updating the database, you will return a Redirect Response back to the client and the client will issue a totally new GET request to the server.
In your case, You can use RedirectToAction to return a 302 response.
db.SaveChanges();
return RedirectToAction("Edit",new {id=payment.Id});
This will tell the browser to issue a new GET request for Edit action method with the new id in the request url. Your GET action method will use this id and get the entity from db and return it.
public ActionResult Edit(int id)
{
var model = db.Payments.Find(id);
return View(model);
}
I strongly recommend you using the PRG pattern.

ASP.NET MVC - A potentially dangerous Request.Form value was detected from the client

Am trying to click save button to update what I have in text editor using ckeditor but I got this error
A potentially dangerous Request.Form value was detected from the client (OPTION_VALUE="Welcome to the Na...").
The controller is shown below
Controller
public ActionResult EditRegistrationGuideline(long id)
{
OPTIONS options = _optionsService.GetOption(id);
return View(options);
}
//
// POST: /Product/Edit/5
[HttpPost]
public ActionResult EditRegistrationGuideline(long id, OPTIONS options)
{
try
{
// TODO: Add update logic here
if (ModelState.IsValid)
{
options.OPTION_ID = id;
options.ACTION_STATUS = 0;
options.CREATED_DATE = DateTime.Now;
_optionsService.AddOption(options);
return RedirectToAction("Index");
}
}
catch
{
//return View();
ModelState.AddModelError("", "We cannot edit this Option. Verify your data entries !");
}
return View();
}
and the view is here
View
#{
//ViewBag.Title = "CreateRegistrationGuideline";
}
<div class="content-header clearfix">
<h1 class="pull-left">
<i class="fa fa-plus"> </i> Edit Registration Guideline
</h1>
<div class="col-xs-3 pull-right">
<input type="button" class="btn btn-block btn-warning" value="Back" onclick="location.href='#Url.Action("IndexRegistrationGuideline", "Options")'" />
</div>
<div class=" box box-body box-primary">
#using (Html.BeginForm("EditRegistrationGuideline", "Options", FormMethod.Post, new { #class = "form-horizontal", #enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#*<h4>OPTIONS</h4>
<hr />*#
#*#Html.ValidationSummary(true)*#
#Html.ValidationSummary(false, null, new { #class = "text-danger" })
<div class="row .col">
<div style="margin-top:20px" class="mainbox col-md-12 col-md-offset-0 col-sm-8 col-sm-offset-2">
<div class="panel panel-info">
<div class="panel-heading">
<div class="panel-title">Edit Option</div>
</div>
<div class="panel-body">
#*<div class="form-group">
#Html.LabelFor(model => model.OPTION_NAME, new { #class = "control-label col-md-2" })
<div class="col-md-10">*#
#*#Html.LabelFor(model => model.OPTION_NAME, new { #class = "control-label col-md-2" })
<div class="col-md-10">*#
#*#Html.EditorFor(model => model.OPTION_NAME)*#
#*#Html.HiddenFor(model => model.faculty_activation_date, new { #Value = System.DateTime.Now })*#
#Html.HiddenFor(model => model.OPTION_NAME)
#Html.ValidationMessageFor(model => model.OPTION_NAME)
<div class="form-group">
#*#Html.LabelFor(model => model.OPTION_VALUE, new { #class = "control-label col-md-2" })*#
<div class="col-md-10">
#Html.LabelFor(model => model.OPTION_VALUE, "Option Value")
#*<textarea class="form-control" placeholder="Enter Option Value" name="OPTION_VALUE" id="editor1"></textarea>*#
#Html.TextAreaFor(model => model.OPTION_VALUE, new { #class = "form-control", #id = "editor1" })
#Html.ValidationMessageFor(model => model.OPTION_VALUE, "", new { #class = "text-danger" })
</div>
</div>
#*<div>
#Html.LabelFor(model => model.OPTION_VALUE, "Option Value")
#Html.TextAreaFor(model => model.OPTION_VALUE, new { #type = "textarea", #id="editor1", #class = "form-control", #placeholder = "Enter Option Value", #autocomplete = "on" })
#Html.ValidationMessageFor(model => model.OPTION_VALUE, null, new { #class = "text-danger" })
</div>*#
#*<div class="form-group">
#Html.LabelFor(model => model.ACTION_STATUS, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ACTION_STATUS)
#Html.ValidationMessageFor(model => model.ACTION_STATUS)
</div>
</div>*#
</div>
<div class="panel-footer">
<div class="panel-title">
<div class="form-actions no-color">
<input type="submit" value="Save" class="btn btn-success" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
}
#*<div>
#Html.ActionLink("Back to List", "Index")
</div>*#
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script src="~/Scripts/jquery-3.1.1.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<script src="https://cdn.ckeditor.com/4.5.7/standard/ckeditor.js"></script>
<script>
$(function () {
CKEDITOR.replace('editor1');
});
</script>
}
Please what do I do.
I use CKEDITOR
XSS error ("A potentially dangerous Request.Form value was detected from the client(...)").
Solution:
[ValidateInput(false)]
Differnce b/w them
AllowHtml:
The AllowHtml attribute can be applied to a Model property and it will disable the validation by ASP.Net MVC only for that particular property
Advantages
The AllowHtml attribute is developed for Model class.
The Scope is limited to specific property of the Model class.
It is the safe and recommended solution.
ValidateInput
The ValidateInput attribute can be applied to a Controller’s Action method and it will disable the validation by ASP.Net MVC only for that particular Action method.
Advantages
The Scope is limited to specific Action method of the Controller class.
If you have multiple properties accepting HTML content, then this method will reduce redundancy.
When Model class is not used for designing Form elements then this attribute is needed.For complete details Link
Just place ValidateInput(false) attribute on controller's action.
[HttpPost]
[ValidateInput(false)]
public ActionResult EditRegistrationGuideline(long id, OPTIONS options)
The other option is to place [AllowHtml] attribute on Model Property, have a look on SO post to get difference between them
ValidateInput(false) vs AllowHtml
I was experiencing a similar issue with the following error message A potentially dangerous Request.Form value was detected from the client.
As an alternative to the previous answers, I found encoding the value passed back to the controller worked. CKEditor allows you to do this by setting the config config.htmlEncodeOutput = true;.
The documentation for this can be found at: https://docs-old.ckeditor.com/ckeditor_api/symbols/CKEDITOR.config.html#.htmlEncodeOutput
I got this error while testing XSS on my site.
This is a very good feature that the model gives us that prevents XSS, CSRF from penetrating your site.
Do not disable it as much as possible.

How to toggle Partial View on Single Submit Button in MVC?

Here is my Code
View
#using (Html.BeginForm("userrights", "Users", FormMethod.Post, new { #class = "form-horizontal", role = "form"}))
{
<div class="form-group">
<div class="col-md-7" style="padding-right:10px">
#Html.TextBoxFor(m => m.companyname, new { #class = "form-control", #placeholder = "Serach By Sponser Name" })
</div>
<div class="clearfix"></div>
</div>
<div class="form-group">
<div class="col-sm-2">
<button type="submit" id="btn_search" value="Search" name="btn_search" class="btn btn-default">Search</button>
</div>
<div class="clearfix"></div>
</div>
</div>
#Html.Partial("_userRightPartial", Model._UserRightPartialView)
<div class="clear"></div>
}
Controller Method
public ActionResult userrights()
{
IEnumerable<MenuListModel> _MenuListModel = _ftwCommonMethods.GetMenuItems();
IEnumerable<SubMenuListModel> _SubMenuListModel = _ftwCommonMethods.GetSubMenuItems("1");
UserRightViewSearch _UserRightViewSearch = new UserRightViewSearch();
UserRightPartialView _UserRightPartialView = new UserRightPartialView();
_UserRightPartialView._SubMenuListModel = _SubMenuListModel;
_UserRightViewSearch._UserRightPartialView = _UserRightPartialView;
_UserRightViewSearch._menu = _MenuListModel;
_UserRightViewSearch.selectedMenu = 0;
return View(_UserRightViewSearch);
}
I want when page first time loads, _userRightPartial partial view should be hidden. After Submitting By Search Button it should appear.
I know it can be possible by Hide and Show DIV. But i want is there other way to do it with MVC Code?

Retrieving dropdown values from partial view during post method

I need to get the selected dropdown value from partial view and included in the CategoryID in the Book class...
[Authorize]
public PartialViewResult GetAllCategory()
{
ProcessSVC.Category newCategory = new ProcessSVC.Category();
newCategory.ChildCategories = obj1.GetAllCategories(String.Empty);
return PartialView(newCategory);
}
GetAllCategory.cshtml (PartialView)
#model MvcAdminTemplate.ProcessSVC.Category
#Html.DropDownListFor(m => m.ParentID, new SelectList(Model.ChildCategories, "ID", "DisplayName"), new { #class = "form-control" })
Create View:
[Authorize]
[HttpPost]
public ActionResult Create()
{
MvcAdminTemplate.ProcessSVC.Book oBook = new ProcessSVC.Book();
return View(oBook);
}
Create.cshtml
#model MvcAdminTemplate.ProcessSVC.Book
#{
ViewBag.Title = "Create";
}
#Html.Partial("_LeftMenu")
<!-- content -->
<h2>Create</h2>
<div class="col-md-10">
#using (Html.BeginForm("Create", "Books", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="row">
<div class="bootstrap-admin-no-table-panel-content bootstrap-admin-panel-content collapse in">
<form class="form-horizontal">
<fieldset>
<legend>Add Book</legend>
<div class="form-group">
<div class="col-lg-2">
#Html.LabelFor(m => m.BookName, new { #class = "control-label" })
</div>
<div class="col-lg-10">
#Html.TextBoxFor(m => m.BookName, new { #class = "form-control", type = "text" })
<p class="help-block"> </p>
</div>
</div>
<div class="form-group">
<div class="col-lg-2">
#Html.LabelFor(m => m.Description, new { #class = " control-label" })
</div>
<div class="col-lg-10">
#Html.TextBoxFor(m => m.Description, new { #class = "form-control ", type = "text" })
<p class="help-block"> </p>
</div>
</div>
<div class="form-group divCategory">
<div class="col-lg-2">
#Html.Label("Parent Category", new { #class = " control-label" })
</div>
<div class="col-lg-10">
#Html.HiddenFor(m => m.BookId, new { #class = "hdn-id" })
#Html.Action("GetAllCategory","Books")
<span class="help-block"> </span>
</div>
<button type="submit" class="btn btn-primary">Save changes</button>
<button type="reset" class="btn btn-default">Cancel</button>
</div>
</fieldset>
</form>
</div>
</div>
}
After submission of the above form i need to get Book attributes and Category "Selected Category".
[Authorize]
[HttpPost]
public ActionResult Create(ProcessSVC.Book oBook)
{
oBook.LanguageID = 1;
_service.AddBooks(oBook.ActualPrice,oBook.ActualPriceString, oBook.Author, oBook.BookId, oBook.BookName, oBook.CategoryID, oBook.Currency, oBook.CurrentPrice, oBook.CurrentPriceString,
oBook.Description, oBook.DiscountPercentage, oBook.DiscountValue, oBook.LanguageID,
oBook.NativeLanguageName, oBook.Publisher);
TempData.Add("SuccessMessage", " New book " + oBook.BookName + " Added !");
return RedirectToAction("Index");
}
Please suggest me.
To correctly bind your model, you need to create the dropdown in the main view. This line in you partial view
#Html.DropDownListFor(m => m.ParentID, ....
will render a select
<select name="ParentID" ...
but you model is expecting a property named CategoryID
In you Create() method, generate the SelectList and assign to a view model property or to ViewBag and then (instead or #Html.Action("GetAllCategory","Books") use
#Html.DropDownListFor(m => m.CategoryID, ....
use this line in your GetAllCategory.cshtml file
#Html.DropDownList("CategoryID", new SelectList(Model.ChildCategories, "ID", "DisplayName"), new { #class = "form-control" })

ActionResult not being called when using [AcceptVerbs(HttpVerbs.Post)]

The ActionResult in the controller is not being called. The page is just refreshing.
Check my code below:
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
#if (#ViewBag.Message != null)
{
<p style="color: #b94a48;">#ViewBag.Message</p>
}
#Html.HiddenFor(model => model.Id)
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">Username</label>
<div class="input-icon">
<i class="fa fa-user"></i>
#Html.TextBoxFor(model => model.UserName, new { #placeholder = "Email", #class = "form-control placeholder-no-fix" })
<p style="color: #b94a48;">#Html.ValidationMessageFor(model => model.UserName)</p>
</div>
</div>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">Password</label>
<div class="input-icon">
<i class="fa fa-lock"></i>
#Html.PasswordFor(model => model.Password, new { #placeholder = "Password", #class = "form-control placeholder-no-fix" })
<p style="color: #b94a48;">#Html.ValidationMessageFor(model => model.Password)</p>
</div>
</div>
<div class="form-actions">
<div>
<label class="checkbox">
#Html.CheckBoxFor(model => model.RememberMe, new { #class = "remember" }) Remember me
</label>
</div>
<button type="submit" class="btn blue pull-right">
Login <i class="m-icon-swapright m-icon-white"></i>
</button>
</div>
</fieldset>
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Login(AccountViewModel model, FormCollection args, string ReturnUrl)
{
}
RouteConfig:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("SJSS", "{controller}/Show/{assetCode}/{action}/{id}", new { controller = "Asset", action = "Index", id = UrlParameter.Optional });
routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Account", action = "Home", id = UrlParameter.Optional });
Try altering your #Html.BeginForm to this:
#Html.BeginForm("***Action Name***", "***Controller Name***", FormMethod.Post)
{
}
You need to specify an "Action", "Controller" and "Form method" for your form. See a code below:
#using (Html.BeginForm("Login", "Account", FormMethod.Post))
{
}
I might be mistaken here but despite the fact that your identation is a bit confusing, I can't find the url which you're posting to, I mean, your form action is empty, even if you submit, how would mvc know which action to call?
Try setting the action and controller parameters on Html.BeginForm.
edit: Check #Roman Denysenko's answer to see an example that might suit your case perfectly.

Resources