Contents

Security › Web Application Security

Never Trust the Client

Anything from the browser can be forged, so validate on the server.

Also known as: don't trust client input, client-side security, trust boundary, untrusted input

Your server can’t trust anything that comes from the client: browser, mobile app or script. Anyone can open DevTools, edit the page, replay a request with curl, or write their own client. All client-side code runs on the user’s machine, under the user’s control.

That includes:

  • form fields, including hidden ones and disabled buttons,
  • query parameters, JSON bodies and headers (User-Agent, Referer, X-Forwarded-For…),
  • cookies and local storage values,
  • file names, content types and sizes,
  • JWT claims, until you’ve verified the signature,
  • “the app only sends valid data” assumptions.

Examples of the mistake

// Browser sends the price
fetch("/checkout", { method: "POST", body: JSON.stringify({ itemId: 7, price: 0.01 }) });

If the server charges whatever price it receives, anyone can buy anything for a cent. The server must look up the price itself.

Client-side onlyWhat an attacker doesServer must
maxlength and JavaScript validationSend a longer or invalid value directlyValidate again
Hidden <input name="role" value="user">Change it to adminNever take roles from the request
Hiding the Delete button for non-adminsCall DELETE /posts/5 directlyCheck permissions per request
isPremium: true in local storageEdit itLook up the plan from the database

What to do

  • Validate all input on the server (input validation), and keep client validation only for usability (form validation).
  • Do authorization on the server for every action, and every object (IDOR).
  • Compute sensitive values yourself: prices, totals, discounts and permissions. Accept only the intent (“buy item 7”) from the client.
  • Be careful with what you bind from requests to your models, so users can’t set fields like is_admin (mass assignment).
  • Verify signatures on tokens and webhooks, and don’t read unverified data.
  • Never put secrets in client code. They can be extracted.

The line between what you control (your server) and what you don’t (everything outside it) is a trust boundary (trust boundary). Check data when it crosses it.