2

我有一个处理大量 VoyagesViewModel 类型的模型的单一视图,在该视图中,用户可以创建新航程或编辑所有活动航程,因此我在该视图中有相同对象类型的不同实例。每个表单都包含以下内容:

<% = Html.Hidden("Voyages["+ i +"].VoyageDetails[" + i2 + "].Id", location.Id)%>
<% = Html.TextBox("Voyages[" + i + "].VoyageDetails[" + i2 + "].ArrivalDate", location.ArrivalDate, new { @class = "dates" })%><% = Html.ValidationMessage("Voyages[" + i + "].VoyageDetails[" + i2 + "].ArrivalDate", "*")%>
<% = Html.TextBox("Voyages[" + i + "].VoyageDetails[" + i2 + "].DepartureDate", location.DepartureDate, new { @class = "dates" })%><% = Html.ValidationMessage("Voyages[" + i + "].VoyageDetails[" + i2 + "].DepartureDate", "*")%>
<% = Html.Hidden("Voyages[" + i + "].VoyageDetails[" + i2 + "].LocationID", location.LocationID)%>
<% = Html.Hidden("Voyages[" + i + "].VoyageDetails[" + i2 + "].LocationName", location.LocationName)%>
<% = Html.Hidden("Voyages[" + i + "].VoyageDetails[" + i2 + "].VesselName", location.VesselName)%>
<% = Html.Hidden("Voyages[" + i + "].VoyageDetails[" + i2 + "].VesselID", location.VesselID)%>
<% = Html.CheckBox("Voyages[" + i + "].VoyageDetails[" + i2 + "].remove", location.remove)%> (remove)

我在该视图中有 8 到 10 个这样的内容,当用户发布表单时(我将所有这些字段放在一个表单中),我希望能够检测用户是否在航程中更改某些内容以保存它,所以我如果没有进行任何更改,则不必保存该特定航次。

要检查这一点,我有一个隐藏字段,我这样做:

 <% = Html.Hidden("Voyages[" + i + "].hash", TamperProofing.GetExpiringHMAC(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model), DateTime.Now.AddMinutes(15)))%>

我使用 HMAC 来获取孔对象的散列版本,但首先我将对象序列化为字符串格式(JSON 格式):

{"Id":22,"VesselName":"CAPTAIN P (CPP)","VesselID":8,"VoyageDetails":[{"Id":58,"ArrivalDate":"\/Date(1259298000000)\/","DepartureDate":"\/Date(1259384400000)\/","LocationID":404,"LocationHash":null,"LocationName":"Balboa, Panama (PABLB)","VesselName":"CAPTAIN P (CPP)","VesselID":8,"Order":0,"Comment":null,"remove":false},{"Id":60,"ArrivalDate":"\/Date(1260248400000)\/","DepartureDate":"\/Date(1260334800000)\/","LocationID":406,"LocationHash":null,"LocationName":"Colon Free Zone, Panama (PACFZ)","VesselName":"CAPTAIN P (CPP)","VesselID":8,"Order":0,"Comment":null,"remove":false},{"Id":61,"ArrivalDate":"\/Date(1260421200000)\/","DepartureDate":"\/Date(1260507600000)\/","LocationID":407,"LocationHash":null,"LocationName":"Cristobal, Panama (PACTB)","VesselName":"CAPTAIN P (CPP)","VesselID":8,"Order":0,"Comment":null,"remove":false},{"Id":62,"ArrivalDate":null,"DepartureDate":null,"LocationID":408,"LocationHash":null,"LocationName":"Manzanillo, Panama (PAMAN)","VesselName":"CAPTAIN P (CPP)","VesselID":8,"Order":0,"Comment":null,"remove":false},{"Id":59,"ArrivalDate":null,"DepartureDate":null,"LocationID":405,"LocationHash":null,"LocationName":"Coco Solo, Panama (PACSO)","VesselName":"CAPTAIN P (CPP)","VesselID":8,"Order":0,"Comment":null,"remove":true}],"newVoyageDetail":null,"isComplete":false,"Code":"A Code","position":0,"hash":null}

因此,当用户发布表单时,我会检查是否对每个航程进行了更改,如下所示:

 var obj = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(_voyage);
     if (TamperProofing.VerifyChanges(obj, hash) == TamperProofing.HMACChanged.True)
    {
       //UPDATE
    }else
    {
       //DO Nothing, is the exact same object
    }

再次序列化它并比较两个哈希值,隐藏的哈希值与最近计算的哈希值,如果匹配则意味着没有任何变化。

一切都很好,我只是想知道,是否还有其他选择可以做到这一点?

我的另一个担忧是序列化和所有 HMAC 事物与序列化生成的这个大字符串所花费的时间与将未更改的对象再次更新到数据库所需的时间相比。

编辑:我不需要知道哪个字段发生了变化,只要发生了变化。

4

1 回答 1

2

如果服务器性能是一个问题,您可以考虑为每条记录创建一个“已更改”字段,并在用户可编辑字段值之一发生更改时使用 Javascript 设置它。

为了确保在低级浏览器或 NoScript 边缘情况下的正确性,一种常见的模式是使用三态值,其中一个状态表示“未知”或“JS 禁用”。例如,您将服务器上的字段初始化为 0(或为空),让您的 JS 代码在加载时将它们全部设置为 1,然后在修改字段时设置为 2。如果您的服务器在 POST 上看到 0/null/empty,那么它会退回到服务器端方法,在这种情况下是您的哈希比较。如果设置为 1,则忽略该记录,如果设置为 2,则自动触发更新。

这样,您可以在 99% 的情况下避免计算哈希,并且仍然正确处理异常值。

这不一定能防止篡改,但您并不太具体说明您要防止哪种篡改。最有效的防篡改手段实际上是首先将对象或信息保持在无法触及的位置,即处于会话状态或加密的 cookie 中。

这些帮助有用?

于 2009-12-08T18:15:10.863 回答