You're right that you could do all the sanitation yourself, and thus be safe from injection. But this is more error-prone, and thus less safe. In other words, doing it yourself introduces more chances for bugs that could lead to injection vulnerabilities.
One problem is that escaping rules could vary from DB to DB. For instance, standard SQL only allows string literals in single quotes ('foo'
), so your sanitation might only escape those; but MySQL allows string literals in double quotes ("foo"
), and if you don't sanitize those as well, you'll have an injection attack if you use MySQL.
If you use PreparedStatement
, the implementation for that interface is provided by the appropriate JDBC Driver
, and that implementation is responsible for escaping your input. This means that the sanitization code is written by the people who wrote the JDBC driver as a whole, and those people presumably know the ins and outs of the DB's specific escaping rules. They've also most likely tested those escaping rules more thoroughly than you'd test your hand-rolled escaping function.
So, if you write preparedStatement.setString(1, name)
, the implementation for that method (again, written by the JDBC driver folks for the DB you're using) could be roughly like:
public void setString(int idx, String value) {
String sanitized = ourPrivateSanitizeMethod(value);
internalSetString(idx, value);
}
(Keep in mind that the above code is an extremely rough sketch; a lot of JDBC drivers actually handle it quite differently, but the principle is basically the same.)
Another problem is that it could be non-obvious whether myUserInputVar
has been sanitized or not. Take the following snippet:
private void updateUser(int name, String id) throws SQLException {
myStat.executeUpdate("UPDATE user SET name=" + name + " WHERE id=" + id);
}
Is that safe? You don't know, because there's nothing in the code to indicate whether name
is sanitized or not. And you can't just re-sanitize "to be on the safe side", because that would change the input (e.g., hello ' world
would become hello '' world
). On the other hand, a prepared statement of UPDATE user SET name=? WHERE id=?
is always safe, because the PreparedStatement
's implementation escapes the inputs before it plugs values into the ?
.