How can ASP.NET MVC enhance security compared to a webform? - asp.net

Since we have separation of layers it should be easier to isolate each layer by security. How does MVC in ASP.NET exploit this to more easily secure a website compared to using a webform?
By security I do not only mean authorization but also anti-hacking security.

1) Decorate Controller/Action by [Authorize] attribute (optionnaly with list of roles that allowed).
Example:
[Authorize("Manager")]
public class MyController:Controller
{
//Each action available only for authorized user
[Authorize(Roles = "Admin;Customer")]
public ActionResult MyAction()
{
//This action is available to the user that have a Manager role and one of next roles: Admin, Customer.
}
public ActionResult AnotherAction()
{
// This action is available for managers only.
}
}
2) Create area at your MVC project, create base controller, that decorated by authorize attribute, and make all controllers at area inherited from decorated controller - that's way you can easy implement admin area for website, for example.
Example:
[Authorize(Roles = "Admin")]
public class BaseController: Controller
{
}
public class My2Controller: BaseController
{
public ActionResult DoSomething()
{
//This action is available only for Admin.
}
}
If you need to protect site from HTML/script injection (user input ... at text field 'surname', that will collect data from admin page 'all site users' and post to his site when you open your page) - you can use next methods.
do nothing - by default MVC validates input, and don't process requests with HTML tags and returns error
use validation - for many kinds of data (names, phones, dates) user should not have possibility to use '<' and '>'. but you don't want user see error page if makes accidental mistake. Than enable client validation.
Use attribute [ValidateInput(false)] and encode incoming data - but user can't input HTML if he really need it.
If you really need user can format his message - use HTML filters for giving possibility input tags from list of permitted. As example: http://htmlagilitypack.codeplex.com/
Provide your own formatting dialect that will be safe and will not use HTML tags
If you need to protect from cross site fake form posting - use [ValidateAntiForgeryToken] attribute with #Html.AntiForgeryToken(); inside your <form> tag. This method generates hidden input with random value and cookie with known key and same value, and attribute check if form contains value, cookie contains value and form value equals to cookies value.
You can create your own security rules, using a bunch of attribute and hidden input on form: for example to set form time-outs.

You can put authorize attributed on each function call with role requirements.

One way users can hack your site is through "Cross-Site Request Forgery" and you can help prevent it by using AntiForgeryToken().
// Your View
#using (Html.BeginForm("Register", "Account"))
{
// Your Form Fields
#Html.AntiForgeryToken("someSalt")
}
// Your Controller
[HttpPost, ValidateAntiForgeryToken(Salt = "someSalt")]
public ActionResult Register(MyViewModel viewModel)
{
// Your Code
}

Related

What the difference between [FromRoute] and [FromBody] in a Web API?

What the difference between [FromRoute] and [FromBody] in a Web API?
[Route("api/Settings")]
public class BandwidthController : Controller
{
// GET: api/Settings
[HttpGet]
public IEnumerable<Setting> GetSettings()
{
return _settingRespository.GetAllSettings();
}
// GET: api/Settings/1
[HttpGet("{facilityId}", Name = "GetTotalBandwidth")]
public IActionResult GetTotalBandwidth([FromRoute] int facilityId)
{
if (!ModelState.IsValid)
{
return HttpBadRequest(ModelState);
}
}
}
Also for PUT:
// PUT: api/Setting/163/10
[HttpPut]
public void UpdateBandwidthChangeHangup([FromRoute] int facilityId, int bandwidthChange)
{
_settingRespository.UpdateBandwidthHangup(facilityId, bandwidthChange);
}
Can I use [FromBody]?
FromBody
Specifies that a parameter or property should be bound using the request body.
When you use FromBody attribute you are specifying that the data is coming from the body of the request body and not from the request URL/URI. You cannot use this attribute with HttpGet requests, only with PUT,POST,and Delete requests. Also you can only use one FromBody attribute tag per action method in Web API (if this has changed in mvc core I could not find anything to support that).
FromRouteAttribute
Summary: Specifies that a parameter or property should be bound using route-data from the current request.
Essentially it FromRoute will look at your route parameters and extract / bind the data based on that. As the route, when called externally, is usually based on the URL. In previous version(s) of web api this is comparable to FromUri.
[HttpGet("{facilityId}", Name = "GetTotalBandwidth")]
public IActionResult GetTotalBandwidth([FromRoute] int facilityId)
So this would try to bind facilityId based on the route parameter with the same name.
Complete route definition: /api/Settings/GetTotalBandwidth/{facilityId}
Complete received url: /api/Settings/GetTotalBandwidth/100
Edit
Based on your last question, here is the corresponding code assuming you want 163 to be bound to facilityId and 10 to bandwidthChange parameters.
// PUT: api/Setting/163/10
[HttpPut("{facilityId}/{bandwidthChange}")] // constructor takes a template as parameter
public void UpdateBandwidthChangeHangup([FromRoute] int facilityId, [FromRoute] int bandwidthChange) // use multiple FromRoute attributes, one for each parameter you are expecting to be bound from the routing data
{
_settingRespository.UpdateBandwidthHangup(facilityId, bandwidthChange);
}
If you had a complex object in one of the parameters and you wanted to send this as the body of the Http Request then you could use FromBody instead of FromRoute on that parameter. Here is an example taken from the Building Your First Web API with ASP.NET Core MVC
[HttpPut("{id}")]
public IActionResult Update([FromRoute] string id, [FromBody] TodoItem item);
There are also other options in MVC Core like FromHeader and FromForm and FromQuery.
Confusion with [FromRoute] versus [FromBody]
Microsoft has done a good job with ASP.NET trying to connect Internet technology into their frameworks and systems. But in the process they often confuse developers by trying to patch their technology solutions on top of what are very simple HTTP and HTML technologies. People walk away assuming their solutions represent how the World Wide Web works...when it simply does not. Routing URL solutions in both their .NET Framework and Core version of ASP.NET are still confusing to many.
Hopefully this helps...
When you create a basic "route" in ASP.NET Core, you are binding your your browser's URL Address Path to a specific Controller Class and its child Method() inside a ASP.NET compiled application. Binding means that Middleware, they designed, sniffs the URL address and tries to take it apart and then match the pieces to code inside your website.
Special Controller-ControllerBase classes handle this process inside ASP.NET using Conventional Routing Templates and Routing Attributes mapped to child Methods inside your classes. That includes the parameters of those methods. This then "routes" all URL browser address path requests to a specific set of code inside your web application in ASP.NET.
Unfortunately, there are too many ways to configure this binding. In the past, it was a bunch of random combinations of Route Templates to controllers & methods, with additional code to map a url to parameters. But that was not always clear for things like query strings. ASP.NET Core has tried to clean up that mess with these new Attribute Routing decorations like [FromRoute], etc.
So how do they work?
[Route("/mypath/{myid}"]
public string MyMethod(int myid){...}
The above matches this browser URL address on the Web:
http://example.com/mypath/5
In its simplest form, ASP.NET MVC or WebAPI uses a "route" text string to map a specific method parameter name to a matching URL path. [FromRoute] helps by binding explicitly a methods parameter name to a matching part of the URL in {}:
[Route("api/[controller]")]// "/api/test"
public class TestController : ControllerBase
{
[HttpGet("{facilityId}")]// "/api/test/26"
public IActionResult GetTotalBandwidth([FromRoute] int facilityId)
{
...
}
}
The [FromRoute] attribute decoration, however, is optional as Middleware in ASP.NET by default tries to map that for you out of the box. If you leave [FromRoute] off, it will try and map your parameter name to the route template name inside {}, as so:
[Route("api/[controller]")]// "/api/test"
public class TestController : ControllerBase
{
[HttpGet("{facilityId}")]// "/api/test/26"
public IActionResult GetTotalBandwidth(int facilityId)
{
...
}
}
[FromQuery], however, only binds to Querystring URL parameters, which lie outside the URL route, according to Microsoft. But I have always considered them as part of the URL. In past iterations of ASP.NET this was left out so people had to fudge a way to grab these values inside the method using Request.QueryString. So this new feature fixes this issue:
[Route("api/[controller]")]// "/api/test"
public class TestController : ControllerBase
{
[HttpGet("{facilityId}")]// "/api/test/26?num=5"
public IActionResult GetTotalBandwidth(int facilityId,[FromQuery] int num)
{
...
}
}
[FromBody] is Completely Different!
Capturing data from a POST has always been tricky. ASP.NET helps solve that by allowing the route URL mapping system to function as normal in listening for the POST and URL request, but using an additional method parameter attribute system to bind to that data coming in using [FromBody]. In the case of POST HTTP VERB types, POST is unique, as a POST has nothing to do with URL mapping. But in this case ASP.NET is using the attribute parameter binding system to grab that form field data for you.
Let's first see how POST form fields work.
When you send HTML form data using a "method=post" like so:
<!doctype html>
<html xml:lang="en-us" lang="en-us">
<head></head>
<body>
<form id="f1" name="f1" method="post" action="">
<input type="text" id="field1" name="field1" size="20" value="" />
<button id="mybutton" name="mybutton" value="submit">Submit</button>
</form>
</body>
</html>
...that sends the form field data packaged inside the "body" of the Request like so as a POST:
HTTP HEADER
Content-Type: text/html
Last-Modified: Fri, 27 Jan 2023 17:45:32 GMT
HTTP BODY
field1=hello&mybutton=submit
Notice the form field POST data is inside a special "body" or payload section of the request post (field1=hello&mybutton=submit). To get that data, you need to use [FromForm](for traditional name-value form POST data) or [FromBody] (special JavaScript JSON Post data only) in ASP.NET parameter decorations, like so:
// Note: In the example below, "field1" only captures one field.
[Route("api/[controller]")]// "/api/test"
public class TestController : ControllerBase
{
[HttpPost]// "/api/test"
public string MyPostMethod([FromForm] string field1)
{
...
}
}
[FromForm] captures regular HTML POST form fields (one field or all fields) as name-value pairs in the WebAPI POST endpoint.
[FromBody] captures the form fields but only as JSON data, requiring an additional content-type of 'application/json' added to the POST request sent to the server. Because HTML Forms cannot do that, you have to use JavaScript when using [FromBody].
So, [FromBody] is almost always used with a POST and has nothing to do with binding a Route Template as part of the URL like [FromRoute] or [FromQuery] might do, but simply captures any POST data typically found inside a POST request form submission sent inside the Http Request package.
Hope that helps!

PRG Pattern in ASP.Net MVC?

I'm new to ASP.Net MVC. In PHP, I always use the PRG pattern even when the post request was invalid. It was pretty easy with session flashes (also user friendly).
In ASP.Net MVC, however, I don't see an easy way to do PRG when the request is invalid. I could think of some ways, but I don't think they are good practices and put some extra unnecessary work.
Moreover, from a couple of articles that I've read, a PRG when the request was invalid was discouraged. If it's a bad practice, then what's the better way to handle unsuccessful post requests? Is it really better off without the PRG? And should I just let the rather annoying browser warnings when a user tries to refresh the page?
In Mvc, it's normal practice to handle your Post Actions as it follows:
[HttpPost]
[ValidateAntiForgeryToken]
public virtual ActionResult LoginForm(LoginViewModel loginViewModel)
{
if (!ModelState.IsValid)
return View("Login", loginViewModel);
return Redirect("/");
}
As you can see, the property ModelState.IsValid will tell you if the request is invalid, therefore giving you the ability to return the same view and display the error messages in the ValidationSummary when the Post request contains an error. This is the code for the View:
#using (Html.BeginForm("LoginForm", "Account"}))
{
#Html.ValidationSummary() // THIS WILL SHOW THE ERROR MESSAGES
#Html.AntiForgeryToken()
#Html.TextBoxFor(x => x.Email)
#Html.PasswordFor(x => x.Password)
<button type="submit">Submit</button>
}
We have been using PRG pattern in our asp.net mvc web apps for about 5 years. The main reason we adopted PRG was to support browser navigation (eg back, forward). Our web apps are used by customer and for front/back office operations. Our typical web page flow is starts with a login, then progresses via many list/detail view. We also incorporate partial views which also have their own viewmodel. List views will have links (GETS) for navigation. Detail views will have forms (POSTS) for navigation.
Keys aspects of our PRG:
We incorporate viewmodels so each view has a viewmodel (all data access is done in the viewmodel).
Each viewmodel has a set() & get() method to maintain the key data field values associated with the most recent instance of the view. The set/get values are persisted in sessionstate.
The set method has a parameter for each value that needs to be set. The get method is just called from the viewmodel constructor to populate the viewmodel's public "key" values.
The viewmodel will also have a public load() method that get all neccessary data for its view.
Our PRG pattern overview:
In controllers we have a separate GET method and a POST method for each action. The GET only displays a view; the POST processes the posted data.
For list (menu) views, the controller GET method calls the target view's set('item key values here') method, then invokes a RedirectToAction to to the target view's controller GET action.
The controller GET method will instantiate the viewmodel (thus causing get of set values), call its load method which uses the set/get key values to get it data, and returns the view/viewmodel.
The controller POST method will either have the viewmodel save the valid posted data then redirect to the next desired page (probably the previous list menu) -OR- if redisplay the current view if the data is invalid.
I have not documented all the PRG flow senarios that we implemented, but the above is the basic flow.
SAMPLE VIEWMODEL SET/GET METHODS
private void GetKeys() {
Hashtable viewModelKeys;
if (SdsuSessionState.Exists("RosterDetail"))
{
viewModelKeys = (Hashtable)SdsuSessionState.Get("RosterDetail");
EventId = (int)viewModelKeys["EventId"];
SessionNo = (int)viewModelKeys["SessionNo"];
viewModelKeys = null;
}
}
public static void SetKeys(int eventId, int sessionNo) {
Hashtable viewModelKeys = new Hashtable();
viewModelKeys.Add("EventId",eventId);
viewModelKeys.Add("SessionNo",sessionNo);
SdsuSessionState.Set("RosterDetail",viewModelKeys);
viewModelKeys = null;
}
SAMPLE CONTROLLER
[AcceptVerbs("Get")]
public ActionResult MenuLink(int eventId, int sessionNo, string submitButton) {
if (submitButton == RosterMenu.Button.PrintPreview) {
// P-R-G: set called viewmodel keys.
RosterDetail.SetKeys(eventId,sessionNo);
// Display page.
return RedirectToAction("Detail","Roster");
}
if (submitButton == RosterMenu.Button.Export) { etc ...}
}

From one Controller to another?

I have a ShopController and an Action method that I call CheckOut. I have [Authorize] before the the Action method, but what if I want the user to continue , after a successfull log in, to another Controller like the CustomersController and the Create View so that the customer can add address and other info into a form?
One option would could be to create a new View with a form within the ShopController, but I guess that isn't a good option!?
One option would could be to create a new View with a form within the
ShopController, but I guess that isn't a good option!?
No. This is the way you want to do it. Create action methods/controllers for different functional/logical pieces of your application. In this case, reading the address is a separate functionality and hence should belong to a separate controller-action method.
You may create a new CustomerController and add a CreateAddress action method ( and view) in that and in your action method which authenticates the user(Login?), use RedirectToAction method to send the user your new view as needed.
public ActionResult Login(string userName,string password)
{
// do your credential verification logic here
return RedirectToAction("CreateAddress","CustomerController");
}

Asp.net MVC Block a user from accessing entire application on certain conditions

I have a website that has for examples pages A, B, C, D,.... I want that the user can only access page A once he has registered. To access the remaining pages the user needs to complete some joining formalities which include making a payment among others.
Now the simple way would be where I add a check in all my pages currently completed to make sure that the pages B, C, D... requested are displayed only if the user has completed all joining formalities. This will need me to re work all those existing pages all over again. Also, all future pages developed will need to remember to add that check.
To come around this I used a custom authorize attribute class that inherits from AuthorizeAttribute and made a check in the overridden OnAuthorization method there as in the snippet below
else if (!SessionCache.FormalitiesCompleted)
{
//force completion of formalities
if (!( string.Equals(filterContext.ActionDescriptor.ActionName, "Index", StringComparison.InvariantCultureIgnoreCase)
|| string.Equals(filterContext.ActionDescriptor.ActionName, "Options", StringComparison.InvariantCultureIgnoreCase)
|| string.Equals(filterContext.ActionDescriptor.ActionName, "Index_B", StringComparison.InvariantCultureIgnoreCase)
|| string.Equals(filterContext.ActionDescriptor.ActionName, "Index_C", StringComparison.InvariantCultureIgnoreCase)
&& string.Equals(filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, "Formalities", StringComparison.InvariantCultureIgnoreCase)))
{
string _action = filterContext.ActionDescriptor.ActionName;
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Formalities", action = _action, area = "FormalitiesArea" }));
}
}
As you can see there are too many OR conditions in the IF. I suspect this will increase as the complexity of the formality increases.
Is there a better way to enforce the user doesn't visit any other page on the site unless the formalities are completed?
Thanks for your time.
You probably should look at the [Authorize attribute] http://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute.aspx If you decorate an action with that attribute only logged in users can access it and others will be redirected to the login page.
For Paid/Registered users, I would inherit from this and make a PaidUserAuthorize attribute:
public class PaidUserAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if(filterContext.Result is HttpUnauthorizedResult)
{
filterContext.Result = new RedirectResult("/PaymentPage");
}
}
}
Therefore decorating an action with
[PaidUserAuthorize(Roles = "PaidUser", "Super User")]
will redirect unpaid users to the payment page.
After a user pays - add them to the PaidUser role. So when they go to the action again they will be allowed access.
You can create an Actin Filter and apply it to the Actions or Classes that you want to restrict access too. In you actions filter, you'll want to override the OnActionExecuting method and implement your checking logic in there. You can allow or deny access to those views based on whatever you want to do
Check this link out for a sample
What about using the [Authorize] annotation in your Controllers? By creating your own AuthorizeAttributes you should be able to customise the authorisation per action based on whatever MembershipProvider you choose to use or create.

Is it possible to pass a method parameter to an attribute for that method?

I want to make a custom AuthorizeAttribute class as described here: Override Authorize Attribute in ASP.NET MVC.
The trick is, whether or not the user is authorized depends not just on what method he is executing, but the parameter as well:
[MyCustomAuthorize(id)]
[HttpGet]
public ActionResult File(Guid id)
{
}
Basically, the user will be authorized to see some Files, but not others, so I want to pass the id to my custom authorize attribute. But I can't seem to do this because the name 'id' isn't in scope.
I know I could do the logic to make sure the user has access to that File at the beginning of the method, but I have several methods that would all need this done, and it would be much cleaner if I could do it as part of the [Authorize] attribute.
No, that's not legal C#.
You can access the RouteValues inside the AuthorizeAttribute subtype, however.
Inside, e.g., OnAuthorization, you can do:
object id = filterContext.RouteData.Values["id"];
Be careful, though. You really need to know what you're doing here. The interaction between authentication, authorization, and caching is complex.
Maybe the last answer in 2011 was correct for that version HOWEVER it is possible. Create a public int (or whatever it is you need) and use that. Example:
public class RestrictToTemplateManagers : AuthorizeAttribute
{
public string GUID { get; set; }
}
[RestrictToTemplateManagers(GUID="ABC")]
public class ImportTemplatesController : Controller
{
}

Resources