Input Validation

Expected level: Working

Input validation checks that data coming into your system has the expected type, format, length and range before you use it. Input is anything you do not control: form fields, query strings, headers, JSON bodies, uploaded files and data from other systems.

Why it must happen on the server

Validation in the browser gives users instant feedback and saves round trips. It is not a security control, because an attacker can skip your page entirely and send requests with a script or an API client. Always validate again on the server. Without it, an attacker who skips the browser checks can send invalid or hostile data straight to your server: broken values in the database, business rules bypassed (a negative quantity, someone else’s ID) and injection payloads.

What to check

  • Type and format: is it a number, a date, an email-shaped string, a valid identifier?
  • Length and size: set maximums for strings, request bodies and uploads.
  • Range and allowed values: quantities above zero, status values from a fixed list.
  • Structure: required fields present, no unexpected extra fields, valid JSON.
  • Business rules: a start date before the end date, a user who may use that product.

Handling bad input

  • Prefer allowlists. Define what is accepted and reject everything else. Blocklists of “bad” characters are easy to bypass.
  • Validate early and reject clearly. Return a helpful error (for example HTTP 400 or 422) without echoing dangerous content back.
  • Encode output after validating. Validation does not replace output encoding: when data is placed into HTML, SQL or a shell command, use the safe mechanism for that context.
  • Use parameterised queries. Never build SQL by joining strings with user input.
  • Check uploads for size, type and name, and never use a user-supplied path directly.
  • Use your framework’s validation features instead of hand-written checks scattered through the code.
Unsafe:  "SELECT * FROM users WHERE name = '" + name + "'"
Safe:    "SELECT * FROM users WHERE name = ?"   with name passed as a parameter

See Common Vulnerabilities for what goes wrong when this is missing, and SQL Fundamentals for the query basics.

Try it

Take an endpoint or form you know and send it bad data: an empty value, a very long string, a negative number, a wrong type. Use an API client such as those in API Testing Tools. Does the server reject each case with a clear error, or does it crash or accept it?

Common mistakes

  • Relying on client-side validation for security.
  • Blocklisting bad characters instead of allowing known good input.
  • Building SQL by joining strings with user input.
  • Using a user-supplied path or file name directly.

Check yourself

  • Why is validating in the browser not enough?
  • Why are allowlists safer than blocklists?
  • What should you check when handling an upload?

Related topics

Terms

Further reading