如何在回发后维护模型值而不暴露它们

时间:2014-09-05 15:17:15

标签: c# asp.net asp.net-mvc razor

我正在使用UserProfile编辑页面,其中只能编辑UserProfile模型的一部分字段。许多字段仅对具有特殊角色的用户可编辑,而UserName字段当然是不可编辑和隐藏的。

现在我正考虑为所有不被用户编辑的字段包含隐藏字段,并像这样装饰我的模型:

[Table("UserProfile")]
public partial class UserProfile
{
    public UserProfile()
    {
        webpages_Roles = new HashSet<Role>();
    }

    [Key]
    public int UserId { get; set; }

    [Required]
    [StringLength(56)]
    [Display(Name="Email")]
    [Editable(false)] // is this the way to go?
    public string UserName { get; set; }

    [Required]
    [Display(Name = "First name")]
    [StringLength(256)]
    public string FirstName { get; set; }

    [Editable(false)] // is this the way to go?
    public bool SomeSetting { get; set; }

    // ... more properties are unimportant for this example
}

其他相关的代码:

    //
    // GET: /Account/Profile

    public ActionResult UserProfile()
    {
        var userProfile = db.UserProfiles.Find(WebSecurity.CurrentUserId);

        return View(userProfile);
    }

    //
    // POST: /Account/Profile

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public ActionResult UserProfile(UserProfile model)
    {
        // if I dont include UserName, validation will fail since it 
        // is now null and the field is [Required]
        if (ModelState.IsValid)
        {
            // if I dont include hidden fields, UserId, UserName
            // and SomeSetting will be null here
            db.Entry(model).State = EntityState.Modified;
            db.SaveChanges();
        }

        return View(model);
    }

相关视图代码:

@Html.HiddenFor(m => m.UserId)
@Html.HiddenFor(m => m.UserName)
@Html.HiddenFor(m => m.SomeSetting)

但是,我担心通过隐藏的输入暴露这些字段。无论如何,聪明或恶意的用户都能够编辑它们吗?我知道我必须包含它们,否则在回发后属性将为null。有人可以开导我吗?

2 个答案:

答案 0 :(得分:1)

你可以做一些事情,比如在模型上生成一个哈希作为属性,这是连接字符串中所有值的哈希值 - 例如:

向ViewModel添加一个新属性(如果这也是您的数据库对象,则可以使用[NotMapped]注释)。:

public string SecurityHash {get;set;}

在帮助程序(或控制器)中创建一个简单的散列函数:

public string CalculateMD5Hash(string input)
{
    // step 1, calculate MD5 hash from input
    MD5 md5 = System.Security.Cryptography.MD5.Create();
    byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
    byte[] hash = md5.ComputeHash(inputBytes);

    // step 2, convert byte array to hex string
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < hash.Length; i++)
    {
        sb.Append(hash[i].ToString("X2"));
    }
    return sb.ToString();
}

现在在控制器中设置哈希值:

//
// GET: /Account/Profile

public ActionResult UserProfile()
{
    var userProfile = db.UserProfiles.Find(WebSecurity.CurrentUserId);
    userProfile.SecurityHash = MyHashHelper.CalculateMD5Hash(userProfile.UserID + userProfile.UserName + userProfile.SomeSetting)
    return View(userProfile);
}

然后在您的视图中,保留您的散列值:

@Html.HiddenFor(m => m.UserId)
@Html.HiddenFor(m => m.UserName)
@Html.HiddenFor(m => m.SomeSetting)
@Html.HiddenFor(m => m.SecurityHash)

最后,您可以在POST后检查您的值是否已被篡改购买重新散列:

//
// POST: /Account/Profile

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult UserProfile(UserProfile model)
{
    string hashCheckVal = MyHashHelper.CalculateMD5Hash(model.UserID + model.UserName + model.SomeSetting)
    if(string.Compare(hashCheckVal, model.SecurityHash) != 0)
    {
        throw new Exception("tampered with!");
    }

    // if I dont include UserName, validation will fail since it 
    // is now null and the field is [Required]
    if (ModelState.IsValid)
    {
        // if I dont include hidden fields, UserId, UserName
        // and SomeSetting will be null here
        db.Entry(model).State = EntityState.Modified;
        db.SaveChanges();
    }

    return View(model);
}

答案 1 :(得分:0)

如果您担心安全性,那么您应该在回发后从数据库中检索您的实体,然后从提交的模型更新可编辑属性。要检索模型,我认为可以将UserId保持为隐藏字段:@Html.HiddenFor(m => m.UserId)

我希望这个答案有所帮助。