在网站开发中,保护用户数据的安全至关重要。本文将介绍一种简单的方法,用于自动加密隐藏表单字段,以防止用户篡改或查看这些字段的值。将使用HtmlHelper扩展、自定义ModelBinder以及Rijndael加密算法来实现这一功能。
在内容管理系统(CMS)中,希望用户只能编辑他们自己创建的帖子。例如,如果用户尝试编辑不属于他们的帖子,那么在后端应该有一个检查机制来确保用户有权限编辑该帖子。如果没有这样的检查,用户可能会恶意地编辑其他人的数据。
将使用Rijndael算法来处理加密。这不是唯一的加密方法,可以根据需要选择任何加密算法。在开始之前,请确保项目中有一个合适的加密类。
首先,需要创建一个处理加密的部分。希望简单地将"HiddenFor()"替换为"EncryptedFor()"。为此,需要创建一个接受目标字段的Linq表达式的HtmlHelper扩展。
' 创建一个加密版本的字段
 _
Public Function EncryptedFor(Of TModel, TProperty)(htmlHelper As HtmlHelper(Of TModel), _
expression As Expression(Of Func(Of TModel, TProperty))) As MvcHtmlString
    Dim name As String
    If TypeOf expression.Body Is MemberExpression Then
        name = DirectCast(expression.Body, MemberExpression).Member.Name
    Else
        Dim op = CType(expression.Body, UnaryExpression).Operand
        name = DirectCast(op, MemberExpression).Member.Name
    End If
    ' 获取值并加密
    Dim value = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData)
    Dim encvalue = RijndaelSimple.Encrypt(value.Model, HttpContext.Current.User.Identity.Name)
    Return New MvcHtmlString( _
    "")
End Function
     
现在,如果回到表单,应该能够切换到EncryptedFor,它将生成隐藏字段:
如所见,字段名已经附加了"-encrypted",并且值是加密的字符串。
接下来,需要处理解密和设置值。MVC模型绑定器显然不知道字段"DatabaseID-encrypted"实际上是为了字段"DatabaseID"。需要创建一个自定义模型绑定器,它在Request.Form中查找字段,解密它,然后设置属性。
Public Class EncryptedModelBinder
    Inherits DefaultModelBinder
    Protected Overrides Sub BindProperty(controllerContext As ControllerContext, _
                                          bindingContext As ModelBindingContext, _
                                          propertyDescriptor As System.ComponentModel.PropertyDescriptor)
        If controllerContext.HttpContext.Request.Form(propertyDescriptor.Name & "-encrypted") IsNot Nothing Then
            Dim decvalue = controllerContext.HttpContext.Request.Form(propertyDescriptor.Name & "-encrypted")
            decvalue = RijndaelSimple.Decrypt(decvalue, "Some unique key")
            propertyDescriptor.SetValue(bindingContext.Model, _
            If(IsNumeric(decvalue), CInt(decvalue), decvalue))
        End If
        MyBase.BindProperty(controllerContext, bindingContext, propertyDescriptor)
    End Sub
End Class
    
需要在Global.asax.vb文件中注册这个:
ModelBinders.Binders.DefaultBinder = New EncryptedModelBinder
    
就是这样!
创建了一个简单的方法,用于从回发中转储request.form的内容,并输出字段的值。如所见,加密的值被传回,但属性已正确设置!
request.form的内容:
DatabaseID-encrypted: SVwvHJ8kzCeIjIN4VZeJLw==
    
模型上的DatabaseID设置为:2012