SQL injection: parameterisation is the fix, not filtering
Lab notes on why escaping and blocklists fail, where prepared statements do not apply, and how to verify a remediation properly.
Why filtering fails
Blocklists of keywords and quote-stripping lose to encoding variations, comment syntax and context differences between database engines. The vulnerability is that data is being parsed as code; the fix is to stop it being parsed as code.
Prepared statements, and where they stop
Parameter binding solves values. It does not cover identifiers — table names, column names and sort direction cannot be bound. Remediation: map user input for identifiers through a server-side allow-list, never interpolate it.
$direction = $request->input('dir') === 'asc' ? 'ASC' : 'DESC';
$column = ['created_at', 'total'][array_search($request->input('sort'), ['date', 'total'], true) ?: 0];
Supporting controls
Least-privilege database accounts, no DROP/ALTER from the application user, generic error messages so failures do not
become an oracle, and query timeouts to blunt blind extraction.
Verification
Retest the original payload plus boolean, time-based and error-based variants and encoding bypasses. Confirm that legitimate sorting and filtering still work, and add a regression test for the specific input that originally worked.