Asp.net mvc 从视图发回时保护实体ID的最有效方法

Asp.net mvc 从视图发回时保护实体ID的最有效方法,asp.net-mvc,viewmodel,code-injection,Asp.net Mvc,Viewmodel,Code Injection,编辑-只需快速编辑,以清晰的问题开始!我想问的是,从视图发回时,保护实体标识符的最有效方法是什么 我一直在考虑在编辑视图模型时如何保护帖子上的ID。让我们以一个实体为例 public class Post { public int Id { get; set; } public string Title { get; set; } public string Content { get; set; } } 及其相应的视图模型: public class PostView

编辑-只需快速编辑,以清晰的问题开始!我想问的是,从视图发回时,保护实体标识符的最有效方法是什么

我一直在考虑在编辑视图模型时如何保护帖子上的ID。让我们以一个实体为例

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
}
及其相应的视图模型:

public class PostViewModel
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
}
现在,当我将此视图模型传递给允许用户编辑它的视图时,我将执行以下操作:

public ActionResult EditPost(PostViewModel viewModel)
{
    Post post = database.Posts.Single(p => p.Id.Equals(viewModel.Id));
    post.Title = viewModel.Title;
    post.Content = viewModel.Content;
    database.Entry(post).State = System.Data.EntityState.Modified;
    database.SaveChanges();

    return View(viewModel);
}
public ActionResult EditPost(int postId, PostViewModel viewModel)
{
    Post post = database.Posts.Single(p => p.Id.Equals(postId));
    // and the rest
}
或者通过参数列表传递ID,如下所示:

public ActionResult EditPost(PostViewModel viewModel)
{
    Post post = database.Posts.Single(p => p.Id.Equals(viewModel.Id));
    post.Title = viewModel.Title;
    post.Content = viewModel.Content;
    database.Entry(post).State = System.Data.EntityState.Modified;
    database.SaveChanges();

    return View(viewModel);
}
public ActionResult EditPost(int postId, PostViewModel viewModel)
{
    Post post = database.Posts.Single(p => p.Id.Equals(postId));
    // and the rest
}
无论哪种方式,我们都需要返回正在更新的实体的标识符以及POST数据。我们如何确保更新的实体是预期的实体

我想我们可以验证用户是否有足够的权限更新此实体。。。但是如果一个用户的帐户被泄露,并且一些随机黑客开始使用他们的帐户注入随机ID怎么办?随机更新各种
Post
s

对于实体,可能建议使用复杂(如GUID)标识符,这会使猜测变得更加困难,但这会让普通用户觉得您漂亮、友好的URL有点吓人,例如,在查看
帖子时,必须传递这些信息


我们如何在这两个世界中取得最佳效果?保持URL干净,但保护我们的实体免受注入攻击?

这是一种直接引用攻击,根据oswap的建议,您可以

  • 通过将id替换为guid,然后将映射保存在内存/会话中,来混淆id
  • 在会话中保留对项目的引用,并确保它与返回的项目相同
我处理这个问题的方法是使用一个属性,我手头没有任何代码,所以您需要

Decorate get action with attribute
on gets, attribute clears item list from session
Pull Item from db
store items id in session for item

decorate post action with attribute    
attribute makes sure modelstate is valid first (saves double validating)
attribute looks in session for id
attribute checks the id against the stored value
if id matches, action can continue
if id doesn't match, an entry is made in modelstate
使用这种方法,您可以保护自己不受他人在burpsuite等工具中摆弄您的ID,或者使用浏览器的控制台模式翻转隐藏字段


此外,作为该过程的开始,始终确保您的获取项目不会盲目地从数据库获取,但首先确保该人确实可以获取该项目,即属于他们的数据集等,正确的?而且不一定让人们不知道用户ABC的帖子的身份是1

也许创建同时具有标识列和guid的表和视图模型会简单一些。所有URL/GET进程都可以使用标识构建,并且可以使用GUI进行所有后期处理。这将使您不必构建一些内存映射、使用会话键、创建操作筛选器等。我和您一样-我希望减少您对会话的依赖程度,因为它是时间敏感的;会话过期后,内存中保留的映射将过期,因此它将始终返回假阴性

不过,这可能会消除数据层中的一些可重用性

编辑: 但我认为最好的保护就像你说的那样——验证编辑记录的帐户是否有权编辑记录。如果您将其与guid(或表单上加密的内容)相结合,则很难随机猜测记录


您还可以尝试向POST表单添加某种哈希算法。比如,散列身份、创建帖子的用户、帖子创建的时间,以及最终用户看不到的实体上的一些随机的不可更新的salt。您还可以包含一些随机的内容(例如页面呈现时的时间标记),以确保每次加载页面时哈希都是唯一的,这将防止在帐户受损时有人使用guid/hash(您需要在单独的字段中发布这些标记)。您的验证过程将匹配发布的散列与实体上相同字段的散列,并且仅在散列匹配时执行更新。但这对我来说似乎有些过分。

如果你通过帖子更新你的价值,用户就不需要查看URL,不是吗?我猜使用guid实际上更安全一些…@samuelcailerie对,但是如果有人恶意编辑了POST值怎么办,无论如何,它都将通过
RouteData
传递,所以我想你可以做一个二级检查,看看路由Id是否与POST Id相同?是的,但我只是引用了你的观点,URL将不再与guid友好:)正如你所说,guid之后是恶意用户更难发现的另一个优势另一个身份证@SamuelCaillerie啊,对了。对于一些人来说,拥有一个干净的URL似乎有点迂腐,但我知道很多用户会将粘贴和电子邮件URL复制给他们的客户,并抱怨是否有一个巨大的查询字符串等。我不喜欢过多地使用
会话
,但你肯定在这里强调了一个好方法。在获取操作时加密GUID,将其存储在表单上的隐藏输入中,在操作启动之前的筛选器中对POST-all进行解密。使用会话的问题是,如果用户打开两个选项卡并获取两个不同的项,则最新的项将“获胜”。任何帖子上的第一个标签都会使用第二个项目(现在是会话中的第二个项目)。真的很喜欢一个可读的身份字段和一个识别身份字段的想法!对于POST表单上的散列算法,我相信有一个
AntiForgeryToken
可以做到这一点。AntiForgeryToken用于xss和POST replay攻击,这是您武库中的一个必要工具,但不是保护您免受DR攻击的工具,您仍然需要混淆/映射保护too@PaulAldred-班恩:我想我描述的第二件事和AntiForgeryToken差不多:)我想我是想到了usi