(Well, yes, it is, but it’s not correct to think so. Here’s why:)
What I will write about is applicable to all kinds of string injection (SQL injection, XSS, header injection, command line injection, etc.) vulnerabilities. Speaking in generalities (in order to encompass them all) will make the exposition much harder to read, so I will instead talk solely about SQL injection. The parallels with other “string injectables” rather than SQL queries (HTML pages, HTTP headers, etc.) are more or less straightforward.
An SQL injection attack happens (mostly) when malicious input breaks out of “value” context and leaks into the SQL “syntax” context. The most common example is when a quote is inserted and everything after the quote is interpreted as SQL statements. The offered remedy is to escape the values (among other things) so that all input will remain in the “value” context.
Here’s what the manual has to say (substitute “escape” for their “quote”) (emphasis mine).
Quote each non numeric user supplied value that is passed to the database with the database-specific string escape function.
Even ignoring that “non numeric”, the troubles start now:
What is “user supplied”? $_GET, $_POST, $_COOKIE, $_REQUEST are clearly user supplied. $_SERVER? Partly so. Database? It depends. (If you answered “no” to this one, go read about Second order SQL injection). Config vars? Nah, they’re fully in our control (hmmm)
First, let’s notice the lesser evil: time. After some of it, chances are that pieces of your code will get rewritten, patched or copy-pasted elsewhere. The assumption about the “user supplied”-ness of these values may change, and the risk of forgetting this assumption is great. (For an artificial example, imagine changing how a “default languge” setting could be redesigned - instead of being a site-wide config variable, it is now a per-user variable and kept in the database. Suddenly it becomes quite user-controllable)
The true “evil” is that we think about security, while we should have been thinking about the correctness of the code (”correct” in the sense of bug-free). Consider this: security holes are a subset of software bugs. If a piece of code is “bug free” (haha) it is also “secure”. And here comes the title: escaping is not a security measure! Escaping is a way to ensure that what we pass as “values” is indeed interpreted as a “value”.
Going back to the above questionary, imagine a config var containing a quote. It is not attacker-conrollable, so it’s not a security risk. It will still break any query it is inserted into withouth being escaped. All security holes are bugs, but not all bugs are security holes. All bugs should be fixed though.
The moral of all this long winded talk is this: don’t think of escaping as a security measure. Don’t think about “tainted” input and whether this $_SERVER index is user-controllable. Don’t “hide” assumptions in your code. Escape every value that goes in a query. This will fix not only the security holes, but also any possible data-related bug.
September 20th, 2008 at 4:36 am - Edit
The only way I’ve really been comfortable with user supplied input in SQL queries is using bind-variables. I’d used PHP’s PDO extension (with Oracle at the time). Don’t know what anyone elses views are on this though.