我们公司目前正在将我们的软件从网络表格改造为MVC,在我们向客户发布之前,它目前处于alpha阶段。简而言之,该应用程序有多个酒店订阅和使用我们的服务。我现在需要确保的核心安全性是没有用户能够访问/修改属于另一家酒店的数据。
我们的模型大多遵循以下两个示例之一:
RoomCategory (structure: model.HotelID)
--------------
ID
HotelID
Room (structure: model.Parent.HotelID)
--------------
ID
RoomCategoryID
HotelID
问题在于,当我在〜/ rooms / edit / 1时,我可以将表单操作URL和隐藏字段值从“1”更改为“50”,而房间ID 50属于另一家酒店。这是一个大问题,因为一个用户实际上可以从另一家酒店“窃取”一个房间并将其自己制作!我们的客户不会很开心。
我正在接近问题的方式......
根据当前登录的用户数据(从会话访问),我们知道用户有权管理的酒店(或酒店)。一种方法是验证每个动作调用并执行以下操作:
app.AuthenticateAccess(room.RoomCategory.HotelID);
这样,AuthenticateAccess功能将阻止进一步操作并“重定向”到Unauthorized / NotFound页面,因为它知道Room ID 50属于HotelID 2,而当前用户无法访问它。当然我认为这是一种安全的方法,但这涉及到每个控制器中所有操作的大量重复函数调用。
我一直在寻找在全球范围内克服这一安全挑战的不同可能性:
我还有其他一些解决方案,比如使用System.Reflection来搜索所有的HotelID属性,并确保当前用户允许保存/创建的所有数据。但无论如何,让我听听你解决这个问题的方法,因为我还不相信任何我能想到的解决方案。
答案 0 :(得分:1)
永远不要相信来自客户端的数据。始终在对数据库进行任何更新/事务之前验证发布的数据。
因此,在您的HttpPost操作方法中,您在继续
之前运行清理检查[HttpPost]
public ActionResult Book(BookingViewModel model)
{
var isGood = hotelService.DoesCurrentUserHasAccessToRoom(model.RoomId);
if(isGood)
{
//Continue with Saving
hotelService.BookRoom(model);
return RedirectToAction("BookingCompleted");
}
return View("NotAuthorized");
}
只要您根据需要将它们放入服务中的小型可重用方法中,就不会有重复的代码。
答案 1 :(得分:1)
其他选项是添加HMAC字段以检查敏感数据(隐藏的id字段)是否未被更改,我使用它一次并且再也不使用它,过度杀伤解决方案。
有人说......
我多次遇到同样的问题,我认为几乎相同的选项,从长远来看,我坚持使用最简单的解决方案GetById存储库方法传递CurrentUserId
,如:
Entity GetById(int id, int? userId);
为什么?
您正在询问细粒度的授权,只有当您知道操作中涉及的确切记录时才能获得授权,那么为什么不在首先负责获取记录的方法中检查该授权呢?
如果记录存在且用户创建该记录然后返回记录,否则返回null,因为该用户不存在该对象,甚至不打扰返回“您不拥有该对象”类型的消息只是一个简单而简单的404“记录不存在”。
如果您愿意,可以使用ActionFilters
尝试相同的方法,类似于this。但是你必须弄清楚如何在filtercontext中检索记录。
对于具有完全访问权限的管理员,如果将null传递给该方法,则可以绕过该检查。