Our company is currently remaking our software from web forms to MVC and it is currently in alpha stage before we release it to our clients. In a nutshell, the app have multiple hotels subscribing and using our service. The core security I now need to ensure is that no user should be able to access/modify data belonging to another hotel.
Our models mostly follow either one of the two examples below:
RoomCategory (structure: model.HotelID)
--------------
ID
HotelID
Room (structure: model.Parent.HotelID)
--------------
ID
RoomCategoryID
HotelID
The problem is that when I am on ~/rooms/edit/1, I can change the form action URL and the hidden field value from '1' to '50' and room ID 50 belongs to another hotel. This is a big problem since one user can actually 'steal' a room from another hotel and make it their own! Our clients will not be very happy.
The way I'm approaching the problem...
From the currently logged-in user data (accessed from session), we know the Hotel (or Hotels) the user has the rights to manage. One way is to authenticate each action call and do something like this:
app.AuthenticateAccess(room.RoomCategory.HotelID);
This way, the AuthenticateAccess function will prevent further operation and 'redirect' to an Unauthorized/NotFound page since it knows that Room ID 50 belongs to HotelID 2 while the current user doesn't have access to it. Sure I think this is a safe way, but this involves a lot of duplicate function calls across all actions in each controller.
I have been looking into different possibilities to overcome this security challenge at a global level:
- Easiest. Encrypt all IDs and hidden fields value though I personally think that even without encryption, the system should be able to authenticate the access each user has.
- Set HotelID in a separate abstract class and let each model (which stores data about one particular hotel) inherits from this abstract class. Perhaps some kind of generics can be done here?
- We use repository/unit of work pattern. Is there some way to limit the data which we can retrieve/update to that of the currently selected Hotel ID only?
- [Your awesome solution goes here.]
I have some other solutions in mind like using System.Reflection to search for all HotelID attributes and ensuring all the data saved/created is allowed for the current user to make. But anyway let me hear your approach to solve this issue since I am not convinced yet with any solution that I can think of.