Intercepting Request in Global.asax - c#

I have an ASP.NET MVC Application using MVC 4.5. I have been instructed to put a query string authorization to the application. The application serves as a data processor for another application at the front.
We decided to append a querystring in the requesting URLs containing a hash code for instance http://dr.appbox.us/DataReport/?passcode=HASHCODE.
The HASHCODE can be checked and if it matches the request is permitted further.
Now I have about 20 controllers in the application, is there a way that I can check if the HASHCODE is valid in global.asax and redirect the user to error page from there?
Also please tell me if there is a way to check if I can bypass this hashcode for Ajax requests in the application.
Thanks

You can use a custom action filter for this. If you create a new class that inherits from ActionFilterAttribute and override the OnActionExecuting method. Here you can validate the passcode and redirect if required.
public class HashCodeCheckFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var passcode = filterContext.HttpContext.Request.QueryString["passcode"];
// Validate passcode
var valid = false;
// If invalid then do some error processing
if (!valid)
{
// Redirect to errro page....
filterContext.Result = new RedirectToRouteResult("NameOfErrorRoute");
return;
}
base.OnActionExecuting(filterContext);
}
}
You can then either use this on specific controllers / actions as an attribute:
[HashCodeCheckFilter]
public class HomeController : Controller
{
// GET: Home
[HashCodeCheckFilter]
public ActionResult Index()
{
return View();
}
}
Or you can register it in Application_Start (Or App_Start/FilterConfig) as a global filter that applies to all requests:
GlobalFilters.Filters.Add(new HashCodeCheckFilterAttribute());
If you want to not check if the request is an ajax request you can check the HTTP_X_REQUESTED_WITH header on the request to see if it equals xmlhttprequest.

is there a way that I can check if the HASHCODE is valid in global.asax and redirect the user to error page from there
I would use a HttpHandler which is better suitable for this. (See documentation here and here and step-by-step tutorial here)
Also please tell me if there is a way to check if I can bypass this hashcode for Ajax requests in the application.
You could check if the HttpContext.Current.Request.Headers["x-requested-with"] is XMLHttpRequest. Then it is an AJAX call and you could skip the authentication step. Additionally, you could set a session variable when receiving the hashcode for the first time and check if that hashcode is still valid when the AJAX request is done. Then you will have a better security then just not checking it.

It sounds to me like you should be looking at implementing an IAuthorizationFilter rather than trying to use Global.asax. An implementation of IAuthorizationFilter will run before any request and you can choose what to do if the hashcode in invalid.

Since you're using asp.net MVC I would look at global action filters within your application. You can register an action filter as a global action filter through your global.asax.
GlobalFilters.Filters.Add(new MyActionFilterAttribute());
Within your action filter you can put the code to check for your hash, this will get executed each time any of your actions are called on the controllers.
public class MyActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if(!filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
{
// CHECK HASH HERE
}
base.OnActionExecuting(filterContext);
}
}
Check out these resources for more information
http://weblogs.asp.net/gunnarpeipman/asp-net-mvc-3-global-action-filters
https://msdn.microsoft.com/en-us/library/system.web.mvc.globalfiltercollection(v=vs.98).aspx

Related

Set ValidateAntiForgeryToken Attribute to work on a condition

I have a generic MVC controller with a POST action. This controller is used in a common project used by multiple applications. We are attempting to add CSRF protection in a staggered release process where we add CSRF protection via the Anti Forgery Token for each application one at a time.
If I add the validation attribute, [ValidateAntiForgeryToken] to this controller but only include the Anti Forgery Token hidden form element in the views of 1 of the applications this will cause havoc for the other applications. How can I apply this attribute based on a condition. Is this possible? Does this need to be done manually similar to the code below? Is there a better way?
[HttpPost]
public ActionResult GenericSection(string nextController, string nextAction, FormCollection form)
{
// Validate anti-forgery token if applicable
if (SessionHandler.CurrentSection.IncludeAntiForgeryToken)
{
try
{
AntiForgery.Validate();
}
catch (Exception ex)
{
// Log error and throw exception
}
}
// If successful continue on and do logic
}
If you decorate the controller action method with ValidateAntiForgeryToken attribute, you can not escape by not putting the hidden field in the view.
You need to figure out a way where, you have the ValidateAntiForgeryToken attribute, have the hidden field for the token in the view but validate the token only when needed.
For the below solution, I assume that the multiple applications you are talking about has web.config file.
What you need to do is, introduce a new configuration in appSettings, such as IsAntiForgeryTokenValidationEnabled or some better shorter name.
Create a new attribute class as following and check the configuration value. If the configuration value is true go ahead and validate the token else just skip it.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CheckAntiForgeryTokenValidation : FilterAttribute, IAuthorizationFilter
{
private readonly IIdentityConfigManager _configManager = CastleClassFactory.Instance.Resolve<IIdentityConfigManager>();
public void OnAuthorization(AuthorizationContext filterContext)
{
var configValue = System.Configuration.ConfigurationManager.AppSettings["IsAntiForgeryTokenValidationEnabled"];
//Do not validate the token if the config value is not provided or it's value is not "true".
if(string.IsNullOrEmpty(configValue) || configValue != "true")
{
return;
}
// Validate the token if the configuration value is "true".
else
{
new ValidateAntiForgeryTokenAttribute().OnAuthorization(filterContext);
}
}
}
OnAuthorization method of above class will be executed before the action method where this attribute is used and validate or not validate the token based on the configuration value.
Now you need to use this attribute on the controller action method as following example.
public class HomeController : Controller
{
[HttpPost]
[CheckAntiForgeryTokenValidation]
public ActionResult Save()
{
// Code of saving.
}
}
After this all the applications which want to validate the AntiForgeryToken need to have the configuration IsAntiForgeryTokenValidationEnabled in their configuration file with value true. The token validation is not available by default, so if existing applications don't have the configurations, they still work without any issues.
I hope this would help you resolve your issue.

how can I validate this invalid property in web api?

I have a user search request object which looks like this:
UserSearchRequest
{
FirstName:"John",
LastName:"Smith",
Expand:["groups","devices"]
}
Expand is an optional parameter. I have validation which checks that the provided Expand parameters are within thin expected set of parameters. The problem is that if a client submits a request like this:
{
FirstName:"John",
LastName:"Smith",
Expand:1
}
By default Web API 2 will pass this request to the controller method with an Expand value of null. So the user won't know that he submitted a bad request and the controller won't be able to identify it as a bad request b/c null is a valid value for this property. Is there a way to override this default behavior?
Action filters are triggered before controller executes its logic. I will give a general idea of what you need to do to get you on the right track.
First requirement for ActionFilter is to create your own filter class by extending ActionFilterAttribute class.
The following is a sample for this
public class ValidateCustomModel : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
//Write your logic to check that all attributes are not null
}
}
Now onto the second step. This step will register your filter in WebApiConfig class so that the application will know that it has to pass requests to this filter wherever the attribute is used
config.Filters.Add(new ValidateModelAttribute());
Now the third step is to call the custom class as an attribute on the controller method that is being executed when user makes a request.
[ValidateModel]
Hope this helps you to customise it for your own logic. Happy coding.

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.

ASP.NET MVC application - user authorization/permissions

I have an ASP.NET MVC web application.
There's a welcome page in my application, and i wish for the user to complete some steps on that page before allowing him to use the application.
I'm trying to accomplish 2 things:
Ensure that the user is always redirected to that page until he completes the required steps. Note: the user is logged in when he is at the welcome page.
Ignore all requests made by that user to any of the controllers, except for a few specific requests to a specific controller.
What is the correct way to do the above?
Thanks.
What i have done is:
Create a class that derives from Controller and add the logic to redirect if not Logged in:
public class CustomController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!LoggedIn) //Here you decide how to check if the user is Logged in
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new
{
controller = "YourLogInControllerName",
action = "YourLoginActionName"
}));
}
else
{
base.OnActionExecuting(filterContext);
}
}
}
Then all Controllers derive from this CustomController class.
Sounds like you could use the session for that, or other (more persistent) storage if you must make sure the visitors finish these 'required steps', so you can store it when they've fininshed them.
I created a custom authorise attribute that redirected the use to my login page if they didn't meet the criteria I set. This then allowed me to use [AuthorizeAdminArea] on my base controller which stopped access to all areas. I then used [AllowAnonymous] to allow access to the login area.
Take a look at the SimpleMemshipProvider
Use a Role and only allow access to the other controllers if the user has this Role. Add the user to this Role when they have completed the necessary steps.
See http://msdn.microsoft.com/en-us/library/9ab2fxh0.aspx

Deny direct URL access to action method

I'm trying to find a way to deny any direct access to my action methods. Basically what I want my users to click on links to navigate instead of typing the URL directly into the address bar in their browsers.
Now I know this can be done by checking the urlreferrer in the request object but this is kind of unreliable and weak because the urlreferrer can easily be modified and some of the security suites actually remove it from the request.
So does any of you know of a way to do this in asp.net mvc3?
Below is the code for the NoDirectAccessAttribute method to restrict direct access to any class or action method that applies the NoDirectAccess attribute
using System;
using System.Web.Mvc;
using System.Web.Routing;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class NoDirectAccessAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.UrlReferrer == null ||
filterContext.HttpContext.Request.Url.Host != filterContext.HttpContext.Request.UrlReferrer.Host)
{
filterContext.Result = new RedirectToRouteResult(new
RouteValueDictionary(new { controller = "Home", action = "Index", area = "" }));
}
}
}
Use the action filter as follows for any controller or action method where you don't want user to request it directly
[NoDirectAccess]
public ActionResult IsUsernameUnique()
In the example above, any direct access to the IsUsernameUnique action method will automatically redirect the user to the Home/Index action method.
i am not sure but maybe this can help you
Consider we have a page with this url
www.yoursite.com/home.aspx
To avoid your user to directly browse this page you can rewrite you url like this
www.yoursite.com/fdmf489ruv30/home.aspx
and in this url the part "fdmf489ruv30" is a unique string that you created it on session_start and will destroy it on session_end
Use this code in Global.asax.cs and Call [NoDirectAccess] to all controllers
//Prevent direct URL access: Call [NoDirectAccess] to all controllers to block
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class NoDirectAccessAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.UrlReferrer == null ||
filterContext.HttpContext.Request.Url.Host != filterContext.HttpContext.Request.UrlReferrer.Host)
{
filterContext.Result = new RedirectToRouteResult(new
RouteValueDictionary(new { controller = "Home", action = "Login", area = "" }));
}
}
}
It is impossible to securely ensure that an authorized user CANNOT spoof a valid request.
After all, if the browser can create a "valid request", then so can an authorized user!
However, this is an unusual requirement, and I'm interested to know what's the motivation behind it?
There are, however, a number of ways to make it harder to spoof the request.
Since no methods will be completely secure, you can try to obfuscate and make it tedious for someone to spoof your requests.
As others have suggested, you could create a random "token" per session and require it in the URL (either as a path or as a querystring).
It would be even better to use JavaScript for this. Render a hidden input with this "token". Then, intercept each link's click event, append the "token" value to the URL, then navigate to the URL.
You can enhance the JavaScript to somehow "process" your token before using it, and minify your JavaScript to obfuscate it ... this would definitely deter even the above-average users from tinkering with your URLs.
There are tons of possible solutions, but the "right" solution really depends on what specific behavior you are trying to prevent.
A quick way of doing that is to set a session containing a random number in the action which is redirecting, also pass the random number as a parameter to the other action.
Inside the other action(redirected one), compare the value of the session with the parameter of the action. If values are equal, the user is getting there by pressing button, otherwise, the user gets there by changing the URL. Hope it helps.
question on Stackoverflow

Categories

Resources