I have to secure my HTML helpers like textboxfor in MVC in a way if user inspects or f12 and change the value I should take the original value or prompt with an error. Is there any way to achieve it except disabling f12 or inspect option through some jquery and keep my value in some storage in the controller level and get again after posting.
I understand these ways around but I want to secure Html Helpers at the Razor level maybe through some custom HTML helper? please suggest .
example:
<div class="form-group">
#Html.TextBoxFor(x => x.PersonNameAr, new { #class = "form-control", #readyonly="readyonly"}) OR
#Html.TextBoxFor(x => x.PersonNameAr, new { #class = "form-control", #disabled="disabled"})
As a developer who wants to make a secure website, you have to pay attention to some details:
If there is something that user is not eligible to see, even if it's in cookie, session, or hidden input, so don't leak it to them.
You can't prevent user to access it's own computer abilities. Google chrome or any other softwares that installed in user's computer is not what you should be able to access it and change it's properties without official permission from user, if you do it, you've hacked users software.
If there is some data that is important to you, and you have to access it from your front-end, and user is not eligible to access it, you have to save it somewhere that user does not have access to it; somewhere like your database table. But HTML tags, cookies, sessionStorage, localStorage,... . These are not good places to save important data, these are the best place to save weak data that not affect your site's functionality.
there is a endless list of attentions to say, but for now that's enough.
If you want to prevent user from overposting data there are multiple ways to do so:
Bind Attribute. You can use Bind attribute in your controller's action to include or exclude some kind of data that user can't pass to your action as model properties.
imagine you have User model as below:
public class User
{
public int UserId { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool IsActive { get; set; }
}
and this is your Edit action:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(User user)
{
//save expense to database
}
And you don't want user to be able to change IsActive property.
if you leave your action like above, any clever user can add extra property to the form and post it to action. But using Bind method like below you can prevent this kind of attack:
public ActionResult Edit([Bind(Include = "UserName", Exclude = "IsActive")]User user)
{
}
You can use ViewModel. Using ViewModel for each view helps you keep things simple and don't loose a point even if you accidentally forgot to use Bind attribute. In this case you can request or retrieve specific properties, and not even prevent attacks, but saving some memory.
Server side checking. In the post methods you can check your input explicitly to make sure user input does not damage your program.
Related
I would like to create a group in my app. In model that group has a field Admin_ID to specify who is the owner. How to include that information in a form? With hidden field? I don't think this would be safe enough solution... Any other ideas?
In model that group has a field Admin_ID to specify who is the owner.
Then apply authentication (see the tutorial for your MVC version) so you know which user is logged in, use authorization to restrict access to admins only and in the controller assign the creating user's ID to the model when it is created:
[Authorize(Roles="Admin")]
public ActionResult Create(SomeModel modelToCreate)
{
// get user, depends on how your project is set up...
var user = GetLoggedOnUser();
modelToCreate.Admin_ID = user.ID;
}
If hidden field is not enough for security - don't include it there, but have a separate action that only does operation on your Admin group.
Sorry, can't give more details, as your question does not contain enough information.
You can always save the Admin_ID in the Session.
To better understand:
public class Group
{
public int A { get; set; }
public string B { get; set; }
public string C { get; set; }
public string ID_Admin { get; set; }
}
where ID_Admin should be automatically generated when someone who is logged in want to submit that form (he need to fill only A, B and C fields). So let's say currently logged user has ID 42, and he want to submit that form (without any knowledge of that additional field of course) - and I want to include that information about his ID in final model submission.
My project has viewmodels labeled like this:
public class locViewModel {
[Required]
public string City { get; set; }
}
If the view does not set a value then how can I detect this? Is this how the [required] works? Also what other kind of tags can I add to fields in a viewModel?
That means that for validation purposes you can do numerous things. For instance, in a View you can have client validation enabled and the form will not submit unless the control that is populating that property has data entered into it.
With a property with the Required attribute, and a Html.ValidationMessageFor(m => m.City, "City is required") you can notify the user on the client-side that it is a required field.
Here is a Great Resource on unobtrusive validation, and an in depth explanation of what you are looking for.
Maybe that's not exactly the solution i need, but this is what i want to do:
i have a company registration form, and each company needs an administrative user. an administrative user may manage multiple companies, so in the company registration form, you can choose an existing user from a dropdown.
the company view model looks something like this:
public class CompanyViewModel {
[Required]
public string Name { get; set; }
// other properties...
public UserViewModel Administrator { get; set; }
public IEnumerable<UserViewModel> AvailableUsers { get; set; }
}
and the user view model looks like this:
public class UserViewModel {
[Required]
public string UserName { get; set; }
[Required]
public string Password { get; set; }
// other properties...
}
in the company registration view:
<div><input type="radiobutton" name="chooseuser" id="existing"/>Choose an Existing User:</div.
<div>#Html.DropDownListFor(m => m.Administrator.Id, Model.AvailableUsers.Select(u => new SelectListItem { Text = string.Format("{0} - {1} {2}", u.UserName, u.FirstName, u.LastName), Value = u.Id.ToString() }), "<Choose existing user>", new { id = "existingusers" })
</div>
<div><input type="radiobutton" name="chooseuser" id="createnew"/>Create a new User:</div>
<div><label>Username:</label> #Html.EditorFor(m => m.Administrator.UserName)</div>
Through javascript, based on radio button selection, the dropdown list is disabled and the new user form shown, or the new user form is hidden and the dropdown list is enabled.
The problem is in the controller Save action after you press save, ModelState.IsValid is false if an existing user is chosen and no data is filled in on the form. If the user chooses to enter a new user, validation succeeds.
What is the best way to handle this?
One option is to load all data for all users into data structures in javascript, and when the value changes on the existing user dropdown, the hidden "create new" form fields can be populated. But this seems lame since passwords would be sitting the html in plain text. i can get fancier and use ajax for a "create new" form and populate a user id on the original form once the new user is saved, but i'd like to keep it all in one form if possible.
Seems liked i'd ideally be able to load the existing user data from the db and populate the model state in the controller Save action, but writing this code manually (even using reflection) seems sloppy. It would be nice if there was a built in method to do this.
Any ideas?
Thanks.
That's a typical scenario which perfectly illustrates the limitations of declarative validation (a.k.a Data Annotations). In order to handle it you could write a custom validation attribute which will be applied to the CompanyViewModel instead of individual properties and will allow you to perform the validation logic based on which radio button the user choose (btw you will need a property on your view model which will represent the radio button selection). The problem with model validators is that you might have some hard time handling the error highlighting.
That's one of the reasons why I use FluentValidation.NET instead of Data Annotations. This allows me to have the validation logic away from the model and done in an imperative way. It also allows me to have conditional validators which apply based on the values of some properties on the view model (in this case this would be the radio button selection).
You may want to consider a custom Modelbinder.
Here's some sample code from my site - this is part of a checkout page for a shopping cart - the user can enter an address but for US StateCd is sent and for non US StateOrProvince is sent. So we look at the country and remove any model errors for the other property that doesn't apply.
I think this is very similar to what you're describing (that you have two scenarios that need different rules but you want to use the same model).
The important code here is bindingContext.ModelState.Remove(...)which removes the model state and allows IsValid to return true.
public class AddressModelBinder : DefaultModelBinder
{
protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
base.OnModelUpdated(controllerContext, bindingContext);
// get the address to validate
var address = (Address)bindingContext.Model;
// remove statecd for non-us
if (address.IsUSA)
{
address.StateOrProvince = string.IsNullOrEmpty(address.StateCd) ? null : CountryCache.GetStateName(address.StateCd);
bindingContext.ModelState.Remove(bindingContext.ModelName + ".StateOrProvince");
}
else
{
address.StateCd = null;
bindingContext.ModelState.Remove(bindingContext.ModelName + ".StateCd");
}
// update country
address.Country = CountryCache.GetCountry(address.CountryCode, true).Name;
// validate US zipcode
if (address.CountryCode == "US")
{
if (new Regex(#"^\d{5}([\-]\d{4})?$", RegexOptions.Compiled).Match(address.ZipOrPostal ?? "").Success == false)
{
bindingContext.ModelState.AddModelError(bindingContext.ModelName + ".ZipOrPostal", "The value " + address.ZipOrPostal + " is not a valid zipcode");
}
}
// all other modelbinding attributes such as [Required] will be processed as normal
}
}
Note: You need to register this modelbinder in global.asax. The modelbinding component is smart enough to let you create differnt model binders for any part of your model if it contains different objects.
ModelBinders.Binders[typeof(UI.Address)] = new AddressModelBinder();
Hope this helps. I think this applies to your situation.
I’ve got an unexpected situation when using Remote Attribute in ASP.NET MVC3.
The model type I used:
using System;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
namespace dTweets.Models
{
// at first time, user should create his account with unique username
// as in twitter.com, user do
public class UserMetadata
{
[HiddenInput]
internal int Identity { get; set; }
[Remote("IsUserExist", "Account")] // at any HttpPost, username should
// be unique – not appropriate if
// updating/editing this model later
[Required(ErrorMessage = "username should be unique")]
public string UserName { get; set; } // user cannot change it, later
[DataType(DataType.Password)]
public string Password { get; set; } // user can also change password, later
[DataType(DataType.MultilineText)]
public string About { get; set; } // Optional field – user can edit it later
}
[MetadataType(typeof(UserMetadata))]
[Bind(Include="UserName, Password, About")]
public partial class User
{
}
}
Remote attribute validates user unique name at account creation time. But when later user wants to update/change his account, Remote attribute did not allow to update model if keeping user unique name the same one.
This is not appropriate result because rarely user changes their unique user name. They just change other fields like About field or password etc.
[Note: at account creation time, I want to check user unique name so I used Remote attribute here, but at later time when updating user account I no longer need Remote attribute]
I must remove Remote attribute for updating this model later.
I want to update/change this model without changing user unique name (remote attribute is applied to this unique name).
one way to do this is to send ID value of this record in AdditionalFields named parameter like
[Remote("IsUserExist", "Account",AdditionalFields = "Identity")]
and then you can check for uniqueness across all rows except the ones that belong to current user. and don't forget to change signature of IsUserEsists action result to receive Identity like
public ActionResutl IsUserExists(string UserName, int Identity)
{
}
Can't you just change server side validation method to something like:
public ActionResult IsUserExists(string userName)
{
if (!UserService.UserNameExists(userName) || (CurrentUser.UserName == userName))
{
return "Yeah. Is it valid.";
}
}
You have current user, because he is logged in. As long as user can only edit his data, this will work.
This is one place where buddy metadata falls short.
Edit/Add scenarios require their own view models. One size fits all scenario validation attributes only work in very trivial business CRUD apps. Add and Edit actions happen in totally different contexts and are only transiently related. This concept is very similar to the DDD bounded context idea.
For a given report, the user will want to have multiple filtering options. This isn't bad when the options are enumerations, and other 'static' data types, however things can get silly fast when you need a select list that is populated by fields stored in a table in the backend.
How do you handle this scenario? I find myself constantly reshaping the View data to accommodate the additional filter fields, but it really is starting to be a bit much tracking not only the selected options, but also the options themselves...
is there not a better way?
I’m currently building out a new reporting section for one of our products at work and am dealing with this same issue. The solution I’ve come up with so far, though it hasn’t been implemented yet so this is still a work in progress, is along the lines of this.
There will be a class that will represent a report filter which will contain some basic info such as the label text and a list of option values.
public enum DisplayStyle
{
DropDown,
ListBox,
RadioList,
CheckList,
TextBox
}
public class FilterOption
{
public string Name { get; set; }
public string Value { get; set; }
public bool Selected { get; set; }
}
public class ReportFilter
{
public string Title { get; set; }
public DisplayStyle Style { get; set; }
public List<FilterOption> Options { get; set; }
}
And then my model will contain a list of these option classes that will be generated based on each report’s needs. I also have a base report class that each report will inherit from so that way I can handle building out the option lists on a per report basis and use one view to handle them all.
public class ReportModel
{
public string Name { get; set; }
public List<ReportFilter> Filters { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
Then inside my view(s) I’ll have some helper methods that will take in those option classes and build out the actual controls for me.
public static string ReportFilter(this HtmlHelper htmlHelper, DisplayStyle displayStyle, FilterOption filterOption)
{
switch (displayStyle)
{
case DisplayStyle.TextBox:
return string.Format("<input type=\"text\"{0}>", filterOption.Selected ? (" value=\"" + filterOption.Value + "\"") : string.Empty);
break;
...
}
}
My route would look like this
Reports/{reportID}/start/{startDate}/end/{endDate}/{*pathInfo}
All reports have a start and end date and then optional filters. The catchall parameter will have lists of filter values in the form of “Customer/1,4,7/Program/45,783”. So it’ll be like a key/value pair in list form. Then when the controller loads it’ll parse out those values into something more meaningful.
public static Dictionary<string, string> RouteParams(string pathInfo)
{
if (string.IsNullOrEmpty(pathInfo))
{
return new Dictionary<string, string>();
}
var values = new Dictionary<string, string>();
// split out params and add to the dictionary object
return values;
}
Then it will pass them off to the report class and validate them to make sure they’re correct for that report. Then when the options are loaded for that report anything that’s been set in the URL will be set to Selected in the ReportOption class so their state can be maintained. Then the filter list and other report data will be added to the model.
For my setup some filters will change when another filters selection changes so there will be some AJAX in here to post the data and get the updated filter options. The drilldown will work sort of like the search options at amazon or newegg when you narrow your search criteria.
I hope that all makes sense to someone beside me. And if anyone has some input on improving it I’d be happy to hear it.
You could go and retrieve the data asynchronously on the screen using jQuery and JsonResults from your MVC application, this is how we populate all of our lists and searches in our applications. I have an example of how it is done here.
This way the view data is loaded on demand, if they don't use the extra filters then they don't have to get the view data and if one selection relates to another then it's clear which set of data you need to retrieve.
Another option, though I don't like this one as much but jQuery solution may not suit you, is to have your model object for your view contain all the view data so that all you need to do is set the single model object and all the lists are loaded directly and strongly typed. This will simplify the view and the back end code because it will be more clear that for this view the only thing you need is a complete version of this model object.
For example if you had two lists for combo boxes then your model might look like:
public class MyViewMode
{
public int MyProperty { get; set; }
public string SomeString { get; set; }
List<string> ComboListA { get; set; }
List<string> ComboListB { get; set; }
}
Hope that makes sense, if not please comment and I'll expand on it.
Ad-hoc filtering on reports is indeed a tricky issue especially when you want to show a custom user interface control based on the data type, do validation, make some filters to be dependent on one another and others not, etc.
One thing I think that is worth considering is the old "build vs buy" issue here. There are specialized tools out there for ad-hoc reporting that do provide a UI for ad-hoc filters help with this such as the usual suspects Crystal Reports, Microsoft's Reporting Services, or our product ActiveReports Server. In ActiveReports Server we support cascading prompts (where available values in prompts depend on one another) and make it easy for anyone, even non-technical business users to modify the prompts (assuming they have permissions obviously). More information about using prompts in ActiveReports Server is here. ActiveReports Server is also, all managed .NET code, and provides ASP.NET controls and web services that allows you to integrate it into your web apps.
Scott Willeke
Product Manager - ActiveReports Server
GrapeCity inc.