3

I have an ASP.NET MVC based application that allows different levels of access depending on the user. The way it currently works is when a user accesses a page, a check is done against the database to determine the rights that user has. The view is then selected based on the level of access that user has. Some users see more data and have more functionality available to them than do others. Each page also makes a variety of ajax calls to display and update the data displayed on the page.

My question is what is the best way to ensure that a particular ajax call originated from the view and was not crafted manually to return or update data the user does not have access to? I would prefer not to have to go to the database to re-check every time an ajax call is made since that was already done when the user initially loaded the page.

zaq
  • 2,571
  • 3
  • 31
  • 39
  • 1
    Why don't you stick with built in membership and roleproviders? This works out of the box and since your ajax calls carry all cookies, all authentication cookies are surely there. – Wiktor Zychla Aug 22 '12 at 22:06
  • 2
    Besides what Wiktor said, I would not do any ajax call to anything that has to do with security in a website, I would just do normal posts. Better be in the safe side man. – Hanlet Escaño Aug 22 '12 at 22:08
  • I do not think there is "best way" to do it... it would depend on how you build your security layer... like if you created them based on asp membership or not.... anyways... I would create a shared security class that caches the security settings from the DB... in that way you do not need to hit your DB on each call... you just read it from memory. – Daniel Aug 22 '12 at 22:19
  • @HanletEscaño How is a normal post safer than an Ajax post? – Charlino Aug 22 '12 at 23:03
  • @Charlino, you cannot compare a normal post with a XMLHTTPRequest, although they might appear they do the same thing, they do not. Even users with no experience can easily see and update these type of posts, while the same is true for normal form posts, it would still be safer. – Hanlet Escaño Aug 22 '12 at 23:18
  • @HanletEscaño I don't follow your reasoning. To the server, they are the exact same thing... an HTTP request with a bunch of headers and a body, so therefore, an ajax post is just as trust worthy as a normal form post. You shouldn't trust one over the other, you should not trust them both equally :-) – Charlino Aug 23 '12 at 00:26

4 Answers4

3

Check out the Authorize Attribute, you can put it on an entire controller or just specific methods within your controller.

Examples:

[Authorize(Roles = "Administrator")]
public class AdminController : Controller
{
 //your code here
}

or

public class AdminController : Controller
{
    //Available to everyone
    public ActionResult Index()
    {
        return View();
    }

    //Just available to users in the Administrator role.
    [Authorize(Roles = "Administrator")]
    public ActionResult AdminOnlyIndex()
    {
        return View();
    }
}

Alternately, you can write a custom Authorize attribute to provide your own logic.

public class CustomAuthorizeAttribute : AuthorizeAttribute 
{           
    protected override bool AuthorizeCore(HttpContextBase httpContext)     
    {
        IPrincipal user = httpContext.User;     
        var validRoles = Roles.Split(',');//Roles will be a parameter when you use the Attribute        
        List<String> userRoles = GetRolesFromDb(user);//This will be a call to your database to get the roles the user is in.

        return validRoles.Intersect(userRoles).Any();
    }
} 

To use:

 [CustomAuthorizeAttribute(Roles = "Admin,Superuser")] 
 public class AdminController : Controller {

 }
Brett
  • 579
  • 3
  • 10
  • I don't think this will work for me because we're not using Windows roles. Our roles are defined in the database and a db call needs to be made in order to ensure membership. – zaq Aug 23 '12 at 19:39
  • I was hoping there might be a way that didn't required going to the database to check every request independently but perhaps this is the only way. Your solution does accomplish this very cleanly. – zaq Aug 24 '12 at 16:48
  • One option might be to cache the user's roles in the session after logging in. – Brett Aug 25 '12 at 00:11
1

If iyou are using a post use

[Authorize]
[ValidateAntiForgeryToken]

If iyou are using a get use

[Authorize]

You can also use this custom attribute

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.

Ellix4u
  • 566
  • 5
  • 9
0

It depends on what type of session mechanisam you are using . Are you using default membership provider ? If not than you can pass user's id and sessionid make sure that user session is valid and user has required permission to make that call .

Pit Digger
  • 9,618
  • 23
  • 78
  • 122
0

Along with the Authorize attribute, you can also allow only Ajax requests using custom attributes as shown here.

Thanks

Max
  • 36
  • 3