ASP.NET MVC ajax call security issue - c#

I am using asp.net mvc3 to develop application.
I protect my pages agaings CSRF by aniforgerytoken.
Imagine that i have Delete button above the datagrid. If user clicks on button, ajax call will post id's of selected items to e.g Countries/Delete action.
Problem is, that user can try to change request's id's (when he look into source code page, he will se $.post(...)), so he can delete countries, which was not selected (in the worst case, for which he hasn't privileges to delete them)
How can i protect my pages againts this? I don't wanna check on delete action, if user really has rights to delete items.
I hear about some ajax call hashing, but didn't found any useful tutorials or something to do that in MVC.

I don't think you need to do anything on the client side. Instead, you should check on the server side that the user has privileges to delete the countries that were selected for deletion, and only delete those that they have privileges to delete.

If you are using a post use the below
[Authorize]
[ValidateAntiForgeryToken]
If you are using a get use
[Authorize]
You can also use this custom attribute below
public class HttpAjaxRequestAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
if (!controllerContext.HttpContext.Request.IsAjaxRequest())
{
throw new Exception("This action " + methodInfo.Name + " can only be called via an Ajax request");
}
return true;
}
}
Then, decorate your action as below
[Authorize]
[HttpAjaxRequest]
public ActionResult FillCity(int State)
{
//code here
}
Remember to "Mark/Tick" if this solve your problem.

Related

ASP.NET MVC route to return user to origin from partial view

I'm using ASP.NET MVC in Visual Studio 2015. The app has the following structure:
MyApp
Controllers
Controller1
Actions
Create
Delete
Details
Edit
IndexPartial
Controller2
Actions
Edit
Controller3
Actions
Edit
Views
Controller1
Create
Delete
Details
Edit
IndexPartial
Controller2
Edit
Controller3
Edit
The app displays Controller1/IndexPartial view on the Controller2/Edit view and on Controller3/Edit. This partial view displays rows of data, each with Edit, Details, Delete buttons which take the user to the Controller1 views for those actions.
When the user is done with the Controller1 action, they need to return to Controller2/Edit or Controller3/Edit via the Back to List button or when the Save/Delete buttons are clicked. But how do we determine where the user originated? Did the user come from the Edit of Controller2 or Controller3?
We've thought of using a session variable. Can RouteConfig.cs be used to track the user's path and help determine where s/he should return? How do we do this via routes in MVC?
Thank you for your help.
Update: This is all done via the server; no JavaScript (Angular, etc.).
The routing engine has nothing to do with what you need. You need to track user navigation and a good way to do this is using ActionFilters.
You can create a custom ActionFilter that checks the UrlReferrer on its OnActionExecuted and decides how to redirect the request to the appropriate Controller/Action.
[Example]
ActionFilter
public class RedirectAfterActionFilter : ActionFilterAttribute, IActionFilter
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
// Your decision logic
if (filterContext.HttpContext.Request.UrlReferrer.AbsolutePath == "something usefull")
{
filterContext.Result = new RedirectToRouteResult("Your Route Name", routeValues: null); // redirect to Home
}
base.OnActionExecuted(filterContext);
}
}
ActionFilter usage
[RedirectAfterActionFilter]
public ActionResult DoSomethingAndGetRedirected()
{
// Save, Edit or Whatever
//...
return new EmptyResult(); // no need to return since the user will be redirected by the filter
}
Extra: Read How to redirect from a action filter if you dislike to use Route names to redirect.
There are two aspects to this:
The "Back to List" link
The "Save/Delete" actions
As far as the "Back to List" link, your controller should be giving the view all the information it needs to produce a viable GUI. Pass an identifier (or even the actual return URL) to the view in the ViewBag as a dynamic property and let the view render the link to the destination.
For the "Save/Delete" actions, it depends on how they are implemented.
If it's all JS with http requests then the same concept above applies.
If you are posting back to the server however, the controller will have to do the redirection with something like RedirectToAction().
How about storing the previous location in a ViewBag and then populate your button href with the ViewBag content...
Or
You can use Url Referrer, which fectches the previous url that linked to current page.
Of course the best method will depend on your implementantion, without seeing your code those two are the best option that I can think of.

Deal with CacheOutput from another website

I have an Action in a Controller that uses the OutputCache attribute
public class PostsController : Controller
{
[OutputCache(3600, VaryByParam="id")]
public ActionResult Index(Guid id)
{
var post = PostRepository.GetById(id);
return View(post);
}
}
When a frontend user requests posts/{id} the page is cached and works very well. But...
The posts are created on another site (a backend in a different assembly), and sometimes, the backend user wants to fix a typo or change the post in any way. She can do this task with no problem (since the backend is not affected by the cache). But, obviously, the frontend user must waits for the cache to invalidate to read the most recent version. Is there a way to trigger a frontend cache refresh when the user updates the post in the backend?

Dealing with Session timeout in ASP.NET MVC

I am working on a MVC application and I have a requirement of dealing with errors and session timeouts by redirecting the user to different error pages based on few parameters in the query string.
The issue I am facing is that i tried to implement this by saving the required parameters from querystring into a session and then redirecting to error pages. But before every HttpGet and Post action in my controllers I am checking if session is active.
So in case of a situation where session values are lost and not able to read them.
How can I implement this thing in any other way?
You need to check whether the session exists, has the fields you expect and is active. If the session does not exist or does not have a fields you expect, then handle the case when the session does not exist yet/expired. If it is not active, then handle the case when the session is no longer active. If everything is ok, then handle the request normally. If the session expired, then handle it as expired.
to check about session, you can use an ActionFilter like this:
public class SessionActiveFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var activeSession = Session["user"];
if (activeSession == null)
//Here, do a redirect
base.OnActionExecuting(filterContext);
}
}
Also, you can use a third option to save the session, like Redis Cache http://blogs.msdn.com/b/webdev/archive/2014/05/12/announcing-asp-net-session-state-provider-for-redis-preview-release.aspx
I know this is a dead story now. But I post this answer for the new comers. Please see the nice tutorial in codeproject about how to check session values in Action Filters.
In a dynamic web application, the session is crucial to hold the information of current logged in user identity/data. So someone without authentication cannot have access to some Page or any ActionResult, to implement this kind of functionality, we need to check session exists (is not null) in every action which required authentication.So, the general method is as follows:
[HttpGet]
public ActionResult Home()
{
if(Session["ID"] == null)
return RedirectToAction("Login","Home");
}
We have to check the above 2 statements each time and in each ActionResult, but it may cause 2 problems.
Repeat Things: As per the good programming stranded, we don't have to repeat the things. Create a module of common code and access it multiple times/repeatedly
Code missing: We have to write code multiple times so it might happen some time we forget to write code in some method or we missed it.
How To Avoid?
The ASP.NET MVC provides a very great mechanism i.e., Action Filters. An action filter is an attribute. You can apply most action filters to either an individual controller action or an entire controller.
If you want to know more about action filter, please click here.
So we will create a custom Action Filter that handles session expiration and if session is null, redirect to Login Action.
Create a new class in your project and copy the following code:
namespace YourNameSpace
{
public class SessionTimeoutAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext ctx = HttpContext.Current;
if (HttpContext.Current.Session["ID"] == null)
{
filterContext.Result = new RedirectResult("~/Home/Login");
return;
}
base.OnActionExecuting(filterContext);
}
}
}
Now our Action Filter is created and we are ready to use it. The following code will show you how we can apply attribute to Action or to complete controller.
Apply to Action
[HttpGet]
[SessionTimeout]
public ActionResult MyProfile()
{
return View();
}
Apply to Controller
[SessionTimeout]
public class HomeController : Controller
{
}
Now all actions of Home Controller will check for session when hit with the help of Action Filter. So we have reduced the code and repetitive things. This is the benefits of Action Filters.

Prevent duplicate calls to action on refresh

I have following actionlink on my view which calls an action on controller.
#Html.ActionLink("Send Request", "SendRequest", new { id = item.CertificateId })
Following URL is formed once link is clicked.
http://localhost:61742/Controller/SendRequest/17
Now when I hit refresh same action is called again which inserts a a duplicate row to my table. Is there a way to prevent duplicate calls to my action or should I add a check before inserting a row to my table.
I even tried changing my view to call HttpPost Action but that also gets called on refresh again.
The problem is due to the fact that the page you are refreshing is your Do Action (SendRequest) page.
I would suggest that your Action returns a redirect back to your original page OR to a "thanks for submitting" page.
You can do this in your SendRequest action (which you should keep as HttpPost), for example:
[HttpPost]
public ActionResult SendRequest(int id)
{
//Do you Send Request logic here
//Redirect the user to another page once complete
return RedirectToAction("Thanks");
}
which will take the user to a URL like: http://localhost:61742/Controller/Thanks/
Of course, the user could still then press the browser "back" button to return to the SendRequest URL, so I would advise putting in as much server side validation as you can to prevent duplicate entries. Other than that though, there isn't much you can do about a user choosing to click the "Send Request" link multiple times.
First, when you're decorating your Action with [HttpPost], the browser should at least alert the user before 'refreshing' (re-posting the data).
Usually, redirection is the the simplest solution to the problem. for example:
[HttpPost]
public ActionResult SendRequest(int id)
{
....
return Redirect("some_url");
}

What is a good method for preventing a user from submitting a form twice?

I have a purchase page and I don't want the user to be able to refresh the page and resubmit the form once they get to the 'order complete' page because it automatically sets them up in our system via database values and charges their card via paypal (only want these to happen ONCE)... I have seen some sites that say 'Don't hit refresh or you will get charged twice!' but that is pretty lame to leave it open to possibility, what's a good way to only allow it to be submitted once or prevent them from refreshing, etc?
PS: I saw a few similar questions: PHP: Stop a Form from being accidentally reprocessed when Back is pressed and How do I stop the Back and Refresh buttons from resubmitting my form? but found no satisfactory answer... an ASP.NET MVC specific answer would be ideal too if there is a mechanism for this.
EDIT: Once they click submit it POSTS to my controller and then the controller does some magic and then returns a view with an order complete message, but if I click refresh on my browser it does the whole 'do you want to resend this form?' that is bad...
The standard solution to this is the POST/REDIRECT/GET pattern. This pattern can be implemented using pretty much any web development platform. You would typically:
Validate submission after POST
if it fails re-render the original entry form with validation errors displayed
if it succeeds, REDIRECT to a confirmation page, or page where you re-display the input - this is the GET part
since the last action was a GET, if the user refreshes at this point, there is no form re-submission to occur.
I 100% agree with RedFilter's generic answer, but wanted to post some relevant code for ASP.NET MVC specifically.
You can use the Post/Redirect/Get (PRG) Pattern to solve the double postback problem.
Here's an graphical illustration of the problem:
What happens is when the user hits refresh, the browser attempts to resubmit the last request it made. If the last request was a post, the browser will attempt to do that.
Most browsers know that this isn't typically what the user wants to do, so will automatically ask:
Chrome -
The page that you're looking for used information that you entered.
Returning to that page might cause any action you took to be repeated.
Do you want to continue?
Firefox - To display this page, Firefox must send information that will repeat any action (such as a search or order confirmation) that was performed earlier.
Safari -
Are you sure you want to send a form again?
To reopen this page Safari must resend a form. This might result in duplicate purchases, comments, or other actions.
Internet Explorer -
To display the webpage again, the web browser needs to
resend the information you've previously submitted.
If you were making a purchase, you should click Cancel to
avoid a duplicate transaction. Otherwise, click Retry to display
the webpage again.
But the PRG pattern helps avoid this altogether by sending the client a redirect message so when the page finally appears, the last request the browser executed was a GET request for the new resource.
Here's a great article on PRG that provides an implementation of the pattern for MVC. It's important to note that you only want to resort to a redirect when an non-idempotent action is performed on the server. In other words, if you have a valid model and have actually persisted the data in some way, then it's important to ensure the request isn't accidentally submitted twice. But if the model is invalid, the current page and model should be returned so the user can make any necessary modifications.
Here's an example Controller:
[HttpGet]
public ActionResult Edit(int id) {
var model = new EditModel();
//...
return View(model);
}
[HttpPost]
public ActionResult Edit(EditModel model) {
if (ModelState.IsValid) {
product = repository.SaveOrUpdate(model);
return RedirectToAction("Details", new { id = product.Id });
}
return View(model);
}
[HttpGet]
public ActionResult Details(int id) {
var model = new DetailModel();
//...
return View(model);
}
While serving up the order confirmation page you can set a token that you also store in the DB/Cache. At the first instance of order confirmation, check for this token's existence and clear the token. If implemented with thread safety, you will not be able to submit the order twice.
This is just one of the many approaches possible.
Note that the PRG pattern does not completely guard against multiple form submissions, as multiple post requests can be fired off even before a single redirect has taken place - this can lead to your form submissions not being idempotent.
Do take note of the answer that has been provided here, which provides a workaround to this issue, which I quote here for convenience:
If you make use of a hidden anti-forgery token in your form (as you
should), you can cache the anti-forgery token on first submit and
remove the token from cache if required, or expire the cached entry
after set amount of time.
You will then be able to check with each request against the cache
whether the specific form has been submitted and reject it if it has.
You don't need to generate your own GUID as this is already being done
when generating the anti-forgery token.
Give each visitor's form a unique ID when the page is first loaded. Note the ID when the form is submitted. Once a form has been submitted with that ID, don't allow any further requests using it. If they click refresh, the same ID will be sent.
Simply do a redirect from the page that does all the nasty stuff to the "Thank you for your order" page. Having done that, the user can hit refresh as many times as he likes.
If you doesn't like redirect the user to other page, then by using my way you dose not need Post/Redirect/Get (PRG) Pattern and the user remain on the current page without fear of the negative effects of re-submitting of the form!
I use a TempData item and a Hidden field (a property in the ViewModel of the form) to keep a same Guid in both sides (Server/Client) and it is my sign to detect if the form is Resubmitting by refresh or not.
Final face of the codes looks like very short and simple:
Action:
[HttpPost]
public virtual ActionResult Order(OrderViewModel vModel)
{
if (this.IsResubmit(vModel)) // << Check Resubmit
{
ViewBag.ErrorMsg = "Form is Resubmitting";
}
else
{
// .... Post codes here without any changes...
}
this.PreventResubmit(vModel);// << Fill TempData & ViewModel PreventResubmit Property
return View(vModel)
}
In View:
#if (!string.IsNullOrEmpty(ViewBag.ErrorMsg))
{
<div>ViewBag.ErrorMsg</div>
}
#using (Html.BeginForm(...)){
#Html.HiddenFor(x=>x.PreventResubmit) // << Put this Hidden Field in the form
// Others codes of the form without any changes
}
In View Model:
public class OrderViewModel: NoResubmitAbstract // << Inherit from NoResubmitAbstract
{
// Without any changes!
}
What do you think?
I make it simple by writing 2 class:
NoResubmitAbstract abstract class
ControllerExtentions static class (An Extension class for System.Web.Mvc.ControllerBase)
ControllerExtentions:
public static class ControllerExtentions
{
[NonAction]
public static bool IsResubmit (this System.Web.Mvc.ControllerBase controller, NoResubmitAbstract vModel)
{
return (Guid)controller.TempData["PreventResubmit"]!= vModel.PreventResubmit;
}
[NonAction]
public static void PreventResubmit(this System.Web.Mvc.ControllerBase controller, params NoResubmitAbstract[] vModels)
{
var preventResubmitGuid = Guid.NewGuid();
controller.TempData["PreventResubmit"] = preventResubmitGuid ;
foreach (var vm in vModels)
{
vm.SetPreventResubmit(preventResubmitGuid);
}
}
}
NoResubmitAbstract:
public abstract class NoResubmitAbstract
{
public Guid PreventResubmit { get; set; }
public void SetPreventResubmit(Guid prs)
{
PreventResubmit = prs;
}
}
Just put them in your MVC project and run it... ;)
Off the top of my head, generate a System.Guid in a hidden field on the GET request of the page and associate it with your checkout/payment. Simply check for it and display a message saying 'Payment already processed.' or such.
Kazi Manzur Rashid wrote about this (together with other asp.net mvc best-practices). He suggests using two filters to handle data transfer between the POST and the follwing GET using TempData.

Categories

Resources