Question

I have a single view that handles a lot of Models of type VoyagesViewModel, in that view the user can create a new voyage or edit all the active voyages, so i have different instances of the same object type in that view. each form contains something like:

<% = 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)

I have 8 to 10 of this in that View, when the user POST the form(I have all this fields in a single form), i want to be able to detect if the user change something in a voyage to save it, so i don't have to save that specific voyage if no changes where made.

To check this i have a hidden field and i do this:

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

Im using HMAC to get a hashed version of the hole object, but first i serialize the object into a string format (JSON Format):

{"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}

So when the user POST the form i check if changes where made to each voyage like this:

 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
    }

Serialize it again and compare both hashes, the one on the hidden against the recently calculated one, if it match it means nothing changed.

All works pretty well, i was just wondering, if there are any other options to do this?

And my other concern is the time that can take the serialization and all the HMAC thing with this large string generated by the Serialization against the time it could take just to Update unchanged object again to the DB.

EDIT: I don't need to know which field changed, just if something changed.

Was it helpful?

Solution

If server performance is a concern, you might consider creating a "changed" field for each record and using Javascript to set it when one of the user-editable field values changes.

To ensure correctness in downlevel browsers or NoScript fringe cases, a common pattern is to use a tri-state value, with one state meaning "unknown" or "JS disabled". For example, you initialize the fields on the server to 0 (or empty), have your JS code set them all to 1 on load, and then to 2 when the field is modified. If your server sees a 0/null/empty on POST, then it falls back on the server-side method, in this case your hash-compare. If it's set to 1, then it ignores that record, and if it's set to 2, then it automatically triggers an update.

This way, you could avoid computing hashes in 99% of cases, and still correctly handle the outliers.

This doesn't necessarily prevent tampering but you weren't too specific about what kind of tampering you're trying to prevent. The most effective means of tamper-proofing is really to keep the object or information out of reach in the first place, i.e. in the session state or an encrypted cookie.

Does that help at all?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top