Input validation is important. Does the field ask for a phone number? Then accept everything except non-numeric characters. Does the field let you select from a number of options? Then accept everything except what is not from the options.

It goes by the saying, "Never trust user input". And it does not only cover the fields visible in UI where the user can type, but also those who are sent in every HTTP request such as cookies, user agent, and referrer. Everything in a HTTP request should be considered a user input.

There's also a client-side validation and server-side validation. Client-side validation refers to the validation process made by the software from the end user before sending a request to the server. While server-side validation refers to the validation process made by the serving application to the data submitted to it.

Client-side validation is great as it provides the user an instant feedback to their input. But never forget to do a server-side validation as the client-side validation may be bypassed.

Of course, you already know that part. And we're not here to talk about SQL Injection.

Now let me tell you a hypothetical situation:

  1. We have two people, John and Jane. They both have an account at Acme Bank. John has $5000 in his account, and Jane has $200 in her account.

  2. John sent $500 to Jane. Now John has $4500 and Jane has $700.

  3. Jane tried sending $1000 to John but the banking system refused with the error message "Insufficient funds."

  4. Jane tried sending -$1000 to John (Yes, it's negative 1000). Now John has $3500 and Jane has $1700.

Why is that the case? Isn't Jane the one who sent the money to John, but why is it that Jane has more money than she has before and John has less money than he has before.

The system failed to validate the input.

It was fine when the system refused the money transfer because of A > B. But it failed to checked for VALUE < 0.

Because of that, the following happened:

  • John has $4500 plus the -$1000 sent by Jane equals $3500.

    4500 + (-1000) = 3500

  • Jane has $700 minus the -$1000 she sent to John equals $1700.

    700 - (-1000) = 1700

Jane managed to take John's money by sending him a negative value.

Except that it was not a hypothetical situation. I encountered the same issue with the points system of a large chain store. There's a feature where you can send points to other users.

The interface says that the maximum points that can be sent is 99999. Then I started wondering... what's the minimum that I can send?

I tried sending 0 (zero) points, but it wouldn't let me. The app only accepts numbers greater than 0. Hey, it's client-side validation!

Now let's try server-side validation. I launched an instance of Charles Web Proxy to see what's going on behind the scenes. There I captured how the app sends requests to their server. And there I was able to send negative points and have the hypothetical scenario work.

Fortunately, their system does not do this anymore. And they updated their app to include SSL pinning.

But still, never ignore the fact that negative numbers exist.