Search code examples
c#phpsecurityencryptiondata-integrity

Storing data on client side - How to protect against manipulation?


General/Introduction:
I work on a project where we have two parts of software. There is a client application that runs on the user's computer and a web application that manages a lot of things related to this project.

The client application reads a lot of different values via IPC from another program, that I don't have the source code of and I don't have the option to change anything in that other program I am reading from.
So, my application collects those values and stores them locally, since it is not always connected to the web application.

Since the web application builds statistics and more out of those values and since the values that are collected are quite important for the whole project, the user should not be able to change them (or at least it should be really hard - I am pretty sure you can't provide 100 % security for data on the client).

Just for the sake of full information: The client application is written in C#, while the web application is based on the Laravel Framework (PHP). But this question is more about theory than exactly how to code this.

My thoughts:
I was thinking about having asymmetric encryption. The client encrypts the data with the public key of the web application server. The data is now stored encrypted. But of course, the client has this public key. Hence, an attacker could just go ahead and encrypt his own manipulated values and store them in the file.

Another thought, that builds upon the encryption, was that I could not only encrypt the data, but the whole file and use a format that is not too obvious. But that is more like security through obscurity and should be avoided as far as I know. Plus one could just decompile the client application and instantly have the format that I am using.

My question:
Is there any way I can provide a decent level of integrity when sending that data to the server? If so, how can it be done?


Solution

  • There are two things you can do:

    1. Give up, because client software authenticity is not the server's problem, and it's theoretically impossible to know for sure that the other end is running the software you intend in a way that isn't spoofable.

    2. If you're using the client software as a data mule, use hash_hmac() and hash_equals() to authenticate the data so it's tamper-evident.

    For example, you could store the MAC by prefixing it to the data:

    $key = random_bytes(32); // Store me for long-term. Maybe per-client?
    
    $data = "foo";
    $mac = hash_hmac('sha256', $data, $key);
    echo $data . $mac;
    

    And then to validate it upon being returned by the client software:

    if (mb_strlen($message, '8bit') < 64) {
        throw new Exception("Invalid message length.");
    }
    $mac = mb_substr($message, 0, 64, '8bit');
    $data = mb_substr($message, 64, null, '8bit');
    $recalc = hash_hmac('sha256', $data, $key);
    if (!hash_equals($recalc, $mac)) {
        throw new Exception("Invalid MAC.");
    }
    // Now we know $data is legitimate.
    

    It is important to use hash_equals() not == or === to prevent timing attacks.

    Note that this renders any such data unavoidably read-only. If you want them to be able to edit data, you're stuck with option 1.