Anti-CSRF implementation in MVC 3 - c#

I would like to implement Anti-CSRF token in Global.asax file of MVC 3.
Is that possible to implement the same in Gloabl.asax file.

Seems what you need is to create a custom filter class which implements IAuthorizationFilter for all POST methods, by checking HttpContext.Request.HttpMethod request:
public class ValidateAntiForgeryTokenEveryPost : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext context)
{
if (context.HttpContext.Request.HttpMethod == "POST")
{
System.Web.Helpers.AntiForgery.Validate();
}
}
}
Then, add the new filter in FilterConfig class:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ValidateAntiForgeryTokenEveryPost());
}
}
Also ensure that the custom filter has registered in Global.asax code:
protected void Application_Start()
{
// other settings
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
// other settings
}
By using global filtering given above, all POST method requests are automatically checks for AntiForgeryToken, no matter if #Html.AntiForgeryToken() is not present inside view pages.
Addendum 1:
It is possible to exclude certain actions from CSRF token checking, what you need is preventing Validate method to execute while a custom attribute class is present. First, create a custom attribute class for validation check:
[AttributeUsage(AttributeTargets.Method)]
public class ExcludeAntiForgeryCheckAttribute : Attribute
{
// other stuff
}
Afterwards, use ActionDescriptor.GetCustomAttributes to get custom attribute type created above:
public class ValidateAntiForgeryTokenEveryPost : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext context)
{
// adapted from Darin Dimitrov (/a/34588606/)
bool isValidate = !context.ActionDescriptor.GetCustomAttributes(typeof(ExcludeAntiForgeryCheckAttribute), true).Any();
// use AND operator (&&) if you want to exclude POST requests marked with custom attribute
// otherwise, use OR operator (||)
if (context.HttpContext.Request.HttpMethod == "POST" && isValidate)
{
System.Web.Helpers.AntiForgery.Validate();
}
}
}
Then you can decorate any methods which should be exempted from CSRF validation token:
[HttpPost]
[ExcludeAntiForgeryCheck]
public ActionResult Index(ViewModel model)
{
// other stuff
return View(model);
}
References:
Check CRSF token by default in ASP.NET MVC (standard version)
Securing all forms using AntiForgeryToken (attribute-based version)

I don't think so. For each request we need to check token.
Please try to use below code in view file.
#Html.AntiForgeryToken()

Related

Return back server generated identifier in response with minimal changes

My objective is to return back HttpContext.TraceIdentifier in the response header for all the APIs.
The return type of all APIs is IActionResult.
I've seen solutions for creating a middlware and overriding messageHandler.
I want to do minimal changes to just return it back.
Currently, I'm not interfering with the default message handler.
As far as I know, you could try to use asp.net core action filter as global filter or as attribute to achieve your requirement.
You could get the httpcontext in the OnActionExecuted method and then you could register the filter for specific controller or as global filter.
More details, you could refer to below codes:
Create a action filter:
public class TestActionFilter : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
var re = context.HttpContext.TraceIdentifier;
context.HttpContext.Response.Headers.Add("TraceIdentifier", re);
}
public void OnActionExecuting(ActionExecutingContext context)
{
//throw new NotImplementedException();
}
}
Add it as attribute in web api controller:
[TypeFilter(typeof(TestActionFilter))]
public class WeatherForecastController : ControllerBase
Or register it as global filter:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options=>options.Filters.Add(typeof(TestActionFilter)));
}
Result:

.net core routing, understand what application called with a generic route

So what I have is a base controller that the following [Route] definition
[Route("{application}/api/[controller]")]
public class BaseController
{
}
All of my current controllers inherit from BaseController.
What I am trying to achieve is that two different application can call my controllers and my code to be aware of what 'application' is calling it.
Application 1 should be able to call /Application1/Api/MyController
Application 2 should be able to call /Application2/Api/MyController
and both requests should go to the same controller but my code should be aware of which application called it.
I thought about having some sort of Middleware and then work out the application from the Request.Path, and then store it in something like HttpContext.Current.Items but that doesn't seem like the correct way to do it.
My personal preference here would be to pass the value as an HTTP header rather than a route parameter, especially if you want it everywhere. It means you don't need a Route attribute and a different URL per application. Using a custom ActionFilterAttribute, there's a bunch of ways you can pass this detail into your action. For example:
public class ApplicationAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (context.HttpContext.Request.Headers.TryGetValue("Application", out var values))
{
// Method 1: This allows you to specify a parameter on your action
context.ActionArguments.Add("application", values.First());
// Method 2: This adds the value into the route data
context.RouteData.Values.Add("Application", values.First());
// Method 3: This will set a property on your controller
if (context.Controller is BaseApplicationController baseController)
{
baseController.Application = values.First();
}
}
base.OnActionExecuting(context);
}
}
And apply it to action methods or your controller:
[Application]
public class FooController : Controller
{
}
Method 1 Usage:
public IActionResult Index(string application)
{
// do something with the parameter passed in
}
Method 2 Usage:
public IActionResult Index(string application)
{
var application = (string)RouteData.Values["Application"];
}
Method 3 Usage:
First, create a base controller that contains the property:
public abstract class BaseApplicationController : Controller
{
public string Application { get; set; }
}
Then make sure your controller inherits from it:
[Application]
public class FooController : BaseApplicationController
{
}
Now you can access the property on your controller:
public IActionResult Index(string application)
{
var application = this.Application;
}
Bonus Method 4:
As an aside, you could use this method to use the URL route value, using the base controller from method 3, modify the attribute to look like this:
public class ApplicationAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (context.Controller is BaseApplicationController baseController)
{
baseController.Application = (string)context.RouteData.Values["application"];
}
base.OnActionExecuting(context);
}
}
Add a route attribute to your controller:
[Route("{application}/api/[controller]/[action]")]
And now you should have the property value on the controller set.
You could move the route template into action and then each action would technically be aware of its caller context by your proposed convention:
[Route("api/[controller]")]
public class YourController : BaseController
{
[HttpGet("{application}")]
public IActionResult Get(string application)
{
if (application == "Application1")
{
...Application1 called
}
if (application == "Application2")
{
...Application2 called
}
...
}
}
Of course, this is your proposed convention and it is not enforced through some custom application authentication in any way so you will have to trust that your callers will correctly identify themselves through this convention.
Another approach, could be to have a base class variable and set that after inspecting the route.
[Route("{application}/api/[controller]")
public class BaseController: Controller
{
protected string CallingApp { get; set; }
public override void OnActionExecuting(ActionExecutingContext ctx)
{
CallingApp = ctx.RouteData.Values["application"];
base.OnActionExecuting(ctx);
}
}

Add authorization to a specific route without adding attribute in mvc

I need to add authorization to a particular route without adding Authorize attribute. Is there any way I can do this in startup? I know I can add Authorize attribute globally to all the routes, but I need to add authorize just to a specific method in a controller without touching any code in that controller.
If you cannot touch code I see the only solution - check using middleware. Lets imagine that route you want to restrict access is POST '/users/register', so you can use ActionFilter registered globally in startup in which you check url and if its url is '/users/register' you are trying to check token and if token is not valid - return 401.
Also you can use Owin middleware
Here is simple example of implementation such logic using ActionFilter
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configuration.Filters.Add(new CheckAuthorizationFilterAttribute());
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
public class CheckAuthorizationFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var requestUri = actionContext.Request.RequestUri.AbsolutePath;
if (requestUri == "/api/users/register")
{
var isTokenValid = ValidateToken();
if (!isTokenValid)
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
return;
}
}
public bool ValidateToken() => false;
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
}
}

Combining AjaxOnlyAttribute and ChildActionOnlyAttribute into one action filter

I want to be able to mark an action on controller to be called both from ajax calls and via RenderAction. The problem is that both this attributes derive or implement different abstractions. One way out is the next:
[AjaxOnly]
PartialViewResult GetViewAjax(int foo) { return GetView(foo); }
[ChildActionOnly]
PartialViewResult GetView(int foo) { ... }
But this is not neat at all.
The AjaxOnly attribute I am talking about is:
public sealed class AjaxOnlyAttribute : ActionFilterAttribute
{
#region Public members
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext == null)
throw new ArgumentNullException("filterContext");
if (filterContext.HttpContext.Request.Headers["X-Requested-With"] != "XMLHttpRequest")
filterContext.Result = new HttpNotFoundResult();
}
#endregion
}
This method is taken from MVC3 futures. An important comment why the condition is not filterContext.HttpContext.Request.IsAjaxRequest() was made by dev team and says the following:
// Dev10 #939671 - If this attribute is going to say AJAX *only*, then we need to check the header
// specifically, as otherwise clients can modify the form or query string to contain the name/value
// pair we're looking for.
This doesn't make any sense. Those 2 attributes are mutually exclusive. If an action is marked with [ChildActionOnly] it can never be directly accessed by the client using an HTTP request (be it synchronous or asynchronous). So if you want an action to ever be accessible using AJAX, you should never decorate it with the [ChildActionOnly] attribute.
I don't know what this [AjaxOnly] attribute is and where it comes from but depending on how it is implemented you might need to tweak it in order to allow child action requests if it relies only on the Request.IsAjaxRequest() method. For example if it is something like this:
public class AjaxOnlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.Result = new HttpNotFoundResult();
}
}
}
you might want to tweak it like this:
public class AjaxOrChildActionOnlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAjaxRequest() &&
!filterContext.IsChildAction
)
{
filterContext.Result = new HttpNotFoundResult();
}
}
}
Inspired on Darin's answer and ChildActionOnlyAttribute's source code, this is the solution I have come up with, which I think it's a tiny bit better:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class AjaxOrChildAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
return controllerContext.IsChildAction || controllerContext.RequestContext.HttpContext.Request.IsAjaxRequest();
}
}
This way, the validation is done before even trying to execute, and the error you get if you type in the url is the exact same one as trying any invalid url.

If all my .Net Controllers/Action need Authorize Attr, Why don't have a attribute to use only those who do not need?

I have a App that need authorization to access all Controllers/Actions. Except the Login and Error Controllers/Actions.
With this scenario, working in a defensive manner is better to keep default restrict access to all Controllers/Actions(without Authorize Attribute) and select with a custom Attribute only those who do not.
Have you guys done something like this?
I have a MVC Filter that execute before all Actions if the Logged User have access to them:
public class ValidatePermissionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
bool isAuthorized = false;
//Logic that verify if logged user have permission to access the requested Controller/Action
...
//Redirect to a page Error if Logged User don't have Authorization
if (!isAuthorized)
{
RouteValueDictionary redirectTargetDictionary = new RouteValueDictionary();
redirectTargetDictionary.Add("action", "Erro");
redirectTargetDictionary.Add("controller", "Index");
context.Result = new RedirectToRouteResult(redirectTargetDictionary);
}
}
}
I'm thinking the best way to do this. I can create a Blank Custom Attribute and put in the Controllers do not need authorization and check it in my Filter:
public class ValidatePermissionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
bool isAuthorized = false;
var DoNotRequiresAuthorizationAttributes = context.ActionDescriptor.GetCustomAttributes(typeof(DoNotRequiresAuthorizationAttribute), false);
if (DoNotRequiresAuthorizationAttributes.Length > 0)
isAuthorized = true;
...
//Redirect to a page Error if Logged User don't have Authorization
if (!isAuthorized)
{
RouteValueDictionary redirectTargetDictionary = new RouteValueDictionary();
redirectTargetDictionary.Add("action", "Erro");
redirectTargetDictionary.Add("controller", "Index");
context.Result = new RedirectToRouteResult(redirectTargetDictionary);
}
}
}
What you expert Guys think?
Update:
Thinking better, I can replace my Filter with a Custom Authorize Attribute and register that to act in all Controllers/Actions in Global.asax:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyCustomAuthorizeAttribute());
}
Update 2:
Instead create a Blank Custom Attribute and put in the Controllers do not need authorization I pass in Parameters of my Custom Authorize the Controllers do not need authorization (in Global.asax):
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ValidatePermissionAttribute("Login", "Erro"));
}
My Authorize Attribute:
public class ValidatePermissionAttribute : AuthorizeAttribute
{
...
public ValidatePermissionAttribute(params string[] optionalControllers)
{
_optionalControllers = optionalControllers;
}
...
}
Update 3:
Conditional Filters is the way to go.
Have you considered using Conditional Filters in ASP.NET MVC 3?
Several ways to handle bulk implementations of attributes:
Create a custom controller base class and implement there.
I think you can use the MVC filter's global filters collection: http://weblogs.asp.net/gunnarpeipman/archive/2010/08/15/asp-net-mvc-3-global-action-filters.aspx
I've been told before the issue with using a filter attribute is that the result can be cached via output caching, and then this wouldn't run. It's better to implement an IAuthorizationFilter interface (or AuthorizeAttribute class) and create an authorization filter instead.
If the goal is just to reduce the need to re-declare the attribute in many places, it seems one could achieve the same by creating one abstract AuthorizeController with the attribute, and any controller whose actions all require authorization can inherit that.

Categories