What they're testing
Whether you know why parameterised queries are safe, or just that you should use them.
The short answer~30 seconds
It happens when user data is concatenated into the SQL string, so it gets PARSED as syntax rather than treated as a value. The one reliable defence is parameterised queries: the statement is sent and compiled first, the parameters separately, so even '; DROP TABLE users; -- remains a string. Manual escaping isn't reliable because the rules differ by engine, by character set, and by position within the statement.
The long answer
Where parameters do NOT help: table names, column names and sort direction — they're structure rather than values, so they can't be bound. That's exactly where injection survives in APIs with ?sort= or ?orderBy=. The only correct handling is an allow-list: map the user's value onto a known set of columns and reject everything else. Not escaping, not a regex.
An ORM reduces the risk without removing it: almost every ORM has a raw-SQL escape hatch, and that's where the hole appears. There's also second-order injection: malicious data is stored safely, then later read back and concatenated into a different query — at which point the source is your own database, so nobody thinks it needs treating as untrusted.
The second layer worth having is least privilege on the application's database account: no DROP, no access to other schemas, not a superuser. It doesn't prevent injection but bounds the damage — and in real incidents the difference between "one table leaked" and "the whole database gone" often lives in a GRANT rather than in the code.
// Injection: dữ liệu trở thành cú pháp
db.query(`SELECT * FROM users WHERE email = '${email}'`);
// An toàn: câu lệnh và dữ liệu đi riêng
db.query('SELECT * FROM users WHERE email = $1', [email]);
// Tên cột KHÔNG tham số hoá được -> danh sách cho phép
const SORTABLE = { name: 'name', created: 'created_at' } as const;
const column = SORTABLE[req.query.sort as keyof typeof SORTABLE] ?? 'created_at';
db.query(`SELECT * FROM users ORDER BY ${column} DESC LIMIT $1`, [limit]);What they'll ask next
?What is blind SQL injection?
When the app returns no query output but still leaks through behaviour — different responses for true and false conditions, or response time when the attacker injects pg_sleep. Which means "we don't show errors" is not a defence.
These lose points
- Filtering keywords like
DROPor--. Deny-lists always have gaps, and they reject legitimate data too.