0

I have a class that keeps track of Property Changes

public class Property
        {
            object _OriginalValue;
            object _ProposedValue;
            DateTime _ProposedDateTime;
            List<Property> _History = new List<Property>();
            public object OriginalValue
            {
                get
                {
                    return _OriginalValue;
                }

                set
                {
                    _OriginalValue = value;
                }
            }
            public object ProposedValue
            {
                get
                {
                    return _ProposedValue;
                }

                set
                {
                    _ProposedDateTime = DateTime.Now;
                    _ProposedValue = value;
                }
            }
            public bool IsDirty
            {
                get
                {

                    if (OriginalValue != ProposedValue)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
            }
        }

This property can be used by classes like

 public class Customer
        {
            protected Property _FirstName = new Property();
            public string FirstName
            {
                get
                {
                    return (string)_FirstName.ProposedValue;
                }

                set
                {
                    _FirstName.ProposedValue = value;
                }
            }

            public object GetOriginalValue(Property Property)
            {
                return Property.OriginalValue;
            }

        }

The question is, is there a way to secure the original value when passing this to a client in an N-Tier architecture?

When a client passes a Customer back into the Service Boundary - by default you can't trust the client. You need to either reload the original values from the database or validate that the original values are untampered. Of course I'm assuming we're going to use business logic based on the current values in the customer to reject or allow an update operation.

Example:

User inserts record with Name Bob.

User fetches record with Name Bob and changes name to Ted. Original Value is Bob, proposed Value is Ted.

User sends Customer to Service to Update Customer.

Everything is good.

*A business rule is now coded into the service that says if the customer's name is Ted - allow the update else throw "unable to update" exception. *

User fetches record with name Ted. User changes name to Darren. User changes name back to Ted - system throws exception. User fetches Ted. User cheats and uses a tool to change the OriginalPropertyValue on the client. The server doesn't refetch the OriginalValue from the database and simply reads the OriginalValue coming from the client.

User bypasses business rule.

Watson
  • 1,385
  • 1
  • 15
  • 36
  • You might want to take a look at [TrackerDog](http://matiasfidemraizer.com/trackerdog) ([GitHub repository](https://github.com/mfidemraizer/trackerdog)). I feel that this will clean up your code a lot :) – Matías Fidemraizer Feb 07 '17 at 22:07
  • Completely off topic. Code provided is simply to demonstrate the idea and is not actual production code. Thanks. – Watson Feb 07 '17 at 22:19
  • Feel free to post a solution using TrackerDog as an example. Make changes on the client, pass the changes to a server and validate that the client didn't change any original values set by a database or have a way to inject the current values from the db into the original values. – Watson Feb 07 '17 at 23:29
  • I was suggesting you TrackerDog just for the part of performing object change tracking, not as a direct answer to your issue. – Matías Fidemraizer Feb 08 '17 at 09:33
  • TrackerDog works for xamarin (ios and android) - targetable by .netstandard 1.6? – Watson Feb 08 '17 at 16:27
  • I would love to port it to work on this scenarios as soon as possible. AFAIK, I can port it to work on .NET Core, since the guys from Castle Project have already released Castle.Core 4.0.0 which is compatible with .NET Core. So first step is .NET Core. If Castle.Core works on .NET Standard 1.6 (or any version), then TrackerDog will do too – Matías Fidemraizer Feb 08 '17 at 18:11
  • Why don't you create an issue about .NET Standard compatibility so I can remember that I need to investigate it? https://github.com/mfidemraizer/trackerdog/issues – Matías Fidemraizer Feb 08 '17 at 18:14

1 Answers1

2

Actually there're more issues with your approach than just checking if original value hasn't been tampered. For example, I suspect that's a multi-user environment where more than an user would be able to edit the same object. That is, the original value mightn't be tampered, but changed before other has already saved a new original value in the database.

I guess you're already applying some kind of optimistic or pessimistic locking on your data...

About your actual concern, probably you need to sign your original value, and whenever you're going to store those objects back in the database, your application layer should check that original value hasn't been tampered (from Wikipedia):

Digital signatures are a standard element of most cryptographic protocol suites, and are commonly used for software distribution, financial transactions, contract management software, and in other cases where it is important to detect forgery or tampering.

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • Matias, before writing this post I've read of two ways to handle this: Repopulate the values on the server or of course apply some technique to make it tamper proof. What I'm really getting after is performance - does it cost more to hit a database or does it cost more to sign the original values. Certain Concurrency checks would block this type of attack (adding where clause to original values{where name=@Name}) as this would ignore the update if you didn't have the original values. – Watson Feb 08 '17 at 16:40
  • @Watson I would go for the signing approach. It's not a complicated process and today's CPU are ultra-powerful :) I'm pretty sure that querying the database has delays, about the total cost, we should make a performance test... It's not the same hitting SQL Server than Redis! – Matías Fidemraizer Feb 08 '17 at 18:09