Unthought.

Input and trust boundaries

Anything arriving from a browser was composed by whoever is sitting there, not by the form that was designed.

Anything arriving from a browser was composed by whoever is sitting there, not by the form that was designed for them. Treating it otherwise is the assumption sitting underneath most of the vulnerability classes worth naming — and client-side validation, whatever else it is good for, is no obstacle whatsoever to somebody who declines to use the form.

Validation happens on the server, against a schema, before a value reaches anything that acts on it. Type, range, length and format are all checked, because a field the interface constrains to a dropdown will arrive one day containing something else.

Queries are parameterized without exception, so that a value can never be interpreted as instruction. String concatenation into a query is the oldest defect in the catalog and it persists because it works fine until somebody types an apostrophe.

Output is escaped according to where it lands, since the rules differ between ordinary text, an attribute, an address, and code. A value safe in one is dangerous in another, and escaping applied at the wrong boundary provides confidence rather than protection.

Uploads are constrained by type, size and count, stored outside the web root, and never served back with a type derived from the filename. A file named as an image and served as a script is the whole of that attack.

Rate limits apply to anything that sends a message, creates a record, or attempts authentication. Without them a form is an open relay for whoever finds it, and the discovery is typically made by a script instead of by a person.

Redirect targets are validated against a list rather than taken from a parameter, because an open redirect turns a trusted domain into a convenient step in somebody else's phishing chain.

Errors returned to a client say what went wrong without describing the system that produced it. A stack trace is diagnostic detail for an operator and reconnaissance for anybody else.

The boundary is drawn deliberately and written down: which values are trusted, where they became trusted, and what verified them. Most confused-deputy defects come from a value that was validated somewhere, passed through three layers, and treated as safe by a function that never saw the check.

Exclusions

What this does not cover.

  • Client-side validation relied on as a control instead of as a convenience.
  • Error responses that expose stack traces or system detail.
  • Uploads served back with a content type inferred from the filename.