EXERCISE 1 — The root cause of SQLi in "data vs code" terms =========================================================== THE ROOT CAUSE (data vs code): A SQL query is CODE — instructions the database parses and executes. The values inside it (a username, a price) are meant to be DATA — inert content the code operates on. SQLi occurs when untrusted input that should be DATA is placed into the query in a way that lets the database parse part of it as CODE. - The database receives one final STRING and parses ALL of it as SQL. It has no record of which characters the developer wrote (trusted code) and which came from the user (untrusted data) — they were concatenated into the same string. So if user input contains SQL syntax, the parser treats it as syntax. - In one line: SQLi = a confusion between DATA and CODE, caused by building the query by string concatenation instead of keeping data on a separate channel. THE CONCATENATED LOGIN QUERY: query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'" With username = "philip" (intended): SELECT * FROM users WHERE username = 'philip' AND password = '...' Here "philip" sits BETWEEN the quotes as a value — pure data. Fine. HOW ' OR '1'='1 CHANGES THE MEANING: The attacker sets username = ' OR '1'='1 After concatenation the string becomes: SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '...' Reading it as the parser does: username = '' <- an empty string (the attacker's leading quote closed the opening quote immediately) OR '1'='1' <- injected BOOLEAN LOGIC, always true AND password = '...' The WHERE clause is now (username='' OR '1'='1') ... and because '1'='1' is ALWAYS TRUE, the OR makes the condition match EVERY row. The query returns all users — typically logging the attacker in as the first row (often an admin), with no valid credentials. WHICH CHARACTER CAUSES THE BREAKOUT, AND WHY: - The SINGLE QUOTE ( ' ) is the breakout character. The developer's query opened a string with a quote ( username = ' ). The attacker's input STARTS with a quote, which the parser reads as the CLOSING quote of that string. Everything the attacker typed AFTER that quote is therefore OUTSIDE the string literal — i.e. in CODE position — so OR '1'='1' is parsed as SQL logic, not as part of the username value. - WHY THE DB CAN'T TELL CODE FROM DATA: it only ever sees the final concatenated string. There is no marker separating "developer's SQL" from "user's value" — they are the same text. The parser applies SQL grammar to the whole thing, so a quote in the data behaves exactly like a quote the developer wrote. The boundary between data and code was destroyed at concatenation time. THE FIX (preview of Chapter 7): - Send the QUERY and the DATA on SEPARATE channels: a parameterized/prepared statement with placeholders: SELECT * FROM users WHERE username = ? AND password = ? - The driver sends the query text (with ?) and the values SEPARATELY. The user's input is bound as a VALUE and is NEVER parsed as SQL — a quote in the username is just a quote character in the data, with no power to break out. Data stays data.