4

What is the best way to protect certain areas of your web application in asp .net mvc. I know we can put [Authorization] attribute at each action, but this seems very tedious since you have to put it all over the place. I'm using membership provider and trying the way I used to do in postback model by setting this protection based on the folder. I use web.config <location> section to protect some folders. I tried this in mvc, it seems to be working, but most of tutorial uses the [Authorization] way.

Which one is the better method?

6 Answers 6

6

I'd highly recommend against putting it in the web.config. Actually, so do Conery, Hanselman, Haack, and Guthrie -- though not highly (p223 of Professional ASP.NET MVC 1.0)

Routes are subject to change, especially in MVC. With the WebForm model, routes are physically represented on the file system so you didn't really have to worry about it. In MVC, routes are "dynamic" for lack of a better term.

You could end up with multiple routes mapping to one controller causing a maintenance pain in the web.config. Worse, you could inadvertently have a route invoke a controller accidentally or forget to update the web.config after adding/modifying routes and leave yourself open.

If, however, you secure your controller instead of the actual route, then you don't need to worry about keeping the web.config in sync with the goings-on of the controllers and changing routes.

Just my 2 cents.

Sign up to request clarification or add additional context in comments.

Comments

5

One possible solution is to create a "protected controller" and use it as a base class for all the areas of your application that you want to protect

[Authorize]
public class ProtectedBaseController : Controller { 

}

public class AdminController : ProtectedBaseController { 
  ...
}

public class Admin2Controller : ProtectedBaseController { 
  ...
}

Comments

3

put [Authorisation] at the top of the controller class. that will lock down the entire controllers actions.

2 Comments

ok thanks. the question is which is better, put it in all of your controllers or set it up in one file web.config. I choose the web.config.
Yeah kinda hard not to agree on that. :)
1

You can put [Authorize] to every contoller you need to secure.

You can add filter GlobalFilters.Add(new AuthorizeAttribute()); in your Startup.cs (or Global.asax) and put [AllowAnonymus] attribute to any controller or action you allow to non-registered users.

If you chose to put [Authorize] to every secure contoller you need to be sure that any controller added by you or anyone other in team will be secure. For this requirement I use such test:

[Fact]
public void AllAuth()
{
    var asm = Assembly.GetAssembly(typeof (HomeController));
    foreach (var type in asm.GetTypes())
    {
        if (typeof(Controller).IsAssignableFrom(type))
        {
            var attrs = type.GetCustomAttributes(typeof (AuthorizeAttribute));
            Assert.True(attrs.Any());
        }
    }
}

I think this way is better than a creating ProtectedContoller, because it make no guarantee that you system have all controllers secure. Also this way doesn't use inheritance, which make project heavier.

Comments

1

Authorization is one way to secure your application; is to apply the attribute to each controller. Another way is to use the new AllowAnonymous attribute on the login and register actions. Making secure decisions based on the current area is a Very Bad Thing and will open your application to vulnerabilities.

Code you can get here

As ASP.NET MVC 4 includes the new AllowAnonymous attribute, so you no more need to write that code.
After setting the AuthorizeAttribute globally in global.asax and then whitelisting will be sufficient. This methods you want to opt out of authorization is considered a best practice in securing your action methods. Thanks.

Comments

0
[Area("AdminPanel")]
public class TestimonialsController : Controller
{
    private  AppDbContext _context;
    private IWebHostEnvironment _env;
    public TestimonialsController(AppDbContext context, IWebHostEnvironment env)
    {
        _context = context;
        _env = env;
    }
    public IActionResult Index()
    {
        return View(_context.Testimonials);
    }
    // GET: AdminPanel/Testimonials/Create
    public IActionResult Create()
    {
        return View();
    }

    // POST: AdminPanel/Testimonials/Create
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create(Testimonial testimonial)
    {
        if (!ModelState.IsValid)
        {
            return View();
        }
        if (!testimonial.Photo.CheckFileType("image/"))
        {
            return View();
        }
        if (!testimonial.Photo.CheckFileSize(200))
        {
            return View();
        }


        testimonial.Image = await testimonial.Photo.SaveFileAsync(_env.WebRootPath, "images");
        await _context.Testimonials.AddAsync(testimonial);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }

    // GET: AdminPanel/Testimonials/Edit/5
    public async Task<IActionResult> Update(int? id)
    {
        if (id == null)
        {
            return BadRequest();
        }
        var testimonial = await _context.Testimonials.FindAsync(id);
        if (testimonial == null)
        {
            return NotFound();
        }
        return View(testimonial);
    }

    // POST: AdminPanel/Testimonials/Edit/5
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Update(int? id, Testimonial newtestimonial)
    {
        if (id==null)
        {
            return BadRequest();
        }
        var oldtestimonial = _context.Testimonials.Find(id);
        if (oldtestimonial == null)
        {
            return NotFound();
        }
        if (!ModelState.IsValid)
        {
            return View();
        }
        if (!newtestimonial.Photo.CheckFileType("image/"))
        {
            return View();
        }
        if (!newtestimonial.Photo.CheckFileSize(200))
        {
            return View();
        }
        var path = Helper.GetPath(_env.WebRootPath, "images", oldtestimonial.Image);
        if (System.IO.File.Exists(path))
        {
            System.IO.File.Delete(path);
        }
        newtestimonial.Image = await newtestimonial.Photo.SaveFileAsync(_env.WebRootPath, "images");
        oldtestimonial.Image = newtestimonial.Image;
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    public async Task<IActionResult> Delete(int id)
    {
        if (id == null)
        {
            return BadRequest();
        }

        var testimonial = _context.Testimonials.Find(id);
        if (testimonial == null)
        {
            return NotFound();
        }
        var path = Helper.GetPath(_env.WebRootPath, "images", testimonial.Image);
        if (System.IO.File.Exists(path))
        {
            System.IO.File.Delete(path);
        }
        _context.Testimonials.Remove(testimonial);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }

}

}

2 Comments

and with extensions it is like that: public static string GetPath(string root, params string[] folders) { string resultPath = root; foreach (var folder in folders) { resultPath = Path.Combine(resultPath,folder); } return resultPath;
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.