Secure Coding Best Practices

Chapter 2 · Practice 2 of 5

Map identifiers like sort columns to an allowlist

From Injection: keep data out of commands

Why it matters

Placeholders work for values, not for table names, column names or sort direction. A sortable table that does ORDER BY ${req.query.sort} is injectable even when every value in the query is parameterized.

OWASP's advice is to keep those identifiers in code: map the user's choice to a known name and reject anything else. It calls user input in table or column names "a symptom of poor design". For sort direction, turn the input into a boolean and choose ASC or DESC yourself.

The same applies to:

  • field names in a dynamic filter (?filter[email]=)
  • JSON paths in document databases
  • index or collection names
  • LIMIT values, which should be parsed as integers and capped

Example

TypeScript
const SORTABLE = { newest: 'created_at', title: 'title', price: 'price_cents' } as const;

export function orderBy(sort: unknown, dir: unknown) {
  const column = SORTABLE[sort as keyof typeof SORTABLE] ?? 'created_at';
  const direction = dir === 'asc' ? 'ASC' : 'DESC';
  return `ORDER BY ${column} ${direction}`; // both values come from code
}