On the Importance of Server-side Validation (or How to Hack Any Web Form)

Note: I don’t endorse bypassing the UX of services as it may lead to unintended consequences which could break said services in unexpected ways.
Ever had to fill out a form on one of those sites that is just designed to be annoying?
I’m not sure how many of these UX interactions are intentionally designed to disrupt users and how many are just incompetently designed.
I’m talking about the kinds of services that companies are required to provide, but would prefer you didn’t use–the “withdraw funds” button; the “contact customer support” button; the “make claim” button.
 
 
Recently, this happened to me.
Twice.
On the same website.
On forms core to the function of the app.
 
 
On the first occasion, the “reset password” button was disabled, despite the fact that the form input was valid. I called customer service (after going round and round in circles with their WhatsApp bot), and was told that:
  1. this was a known issue;
  1. some characters in a password would silently trigger invalidity;
  1. the only way to enable the button was if the link had been sent by a customer services representative specifically–it was impossible to reset your own password without calling a help desk!
 
When I hit the second occurrence of faulty forms on their site, it was due to a character max length on a form field not allowing me to input a correct value.
I’ve always known that server-side input validation is important–requests can be sent from any source with any information provided by a malicious user, but I also assumed that this kind of hacking is only accessible to a small fraction of people having the correct know-how to override JavaScript in the browser.
Out of interest, I wanted to see what you would need to do to override a buggy form like this. The resulting learnings proved just how accessible this method is and how important security measures like server-side validation, CSRF tokens, etc. truly are.
 
Here are three simple methods an attacker might use to bypass form security.

Method 1: Copy and Edit the Request

Right-click the page and select inspect to open the Chrome DevTools.
Open the Network tab and click submit on the form.
For the request that was fired (where you can see your form data), right-click on the request in the table and select Copy > Copy as cURL. You can then paste this into your terminal, change the body of the request and make the request again.
If the service only uses the tokens as authentication which are sent in the header, then this may work (as it also copies the token sent as a header). If cookies are used for authentication (managed by the browser), then the request may be rejected. For example, if a CSRF token is stored as a cookie by the browser.

Method 2: Edit the HTML

Right-click the page and select inspect to open the Chrome DevTools.
Click the click an element in the page to inspect it icon in the top-left and click on the form element in the page, this will focus the HTML element in the inspector.
Double click the attributes in the HTML and type to change them, for example, you can change maxlength to be longer, which will prevent the input from truncating text.
If the service uses JavaScript to validate inputs via a secondary method, this will be insufficient to send a request, as it will still be rejected by client-side validation.

Method 3: Override the JavaScript

Right-click the page and select inspect to open the Chrome DevTools.
Go to the Sources tab and go to Pages, which will show the JS source files for all the current page.
Inspect the code and find the JavaScript file that does form validation–this code is not editable, and therefore, the attacker will need to override the file.
Right-click the file and select Override content.
You may need to select a folder for Chrome to store your overrides in and select the checkbox to Enable Local Overrides.
This will create a copy of the JavaScript file locally, which you can edit in the Sources > Overrides tab–simply change the form validation logic, hard refresh the page (ignore cache) and Chrome will now be using your custom local JS file with validation disabled.
If it’s a very minor change need, it’s quite simple to search through the file and find the one place to change the max length.
Obfuscation/ minification can make this more difficult to do and put-off would-be attackers.

In Conclusion

You can’t trust what’s coming from your frontend.
Even if you have control over the JavaScript that gets executed in the users’ browsers, it’s very easy for the user to override your code, which can bypass any frontend validation put in place without needing to understand or replicate any of the authentication methods used by your website.
Validate your inputs on the backend!
 
P.S. if you intentionally create features designed to prevent your users from making use of services they are entitled to–don’t do that please!