This came up in a discussion on Reddit:
https://www.reddit.com/r/PHP/comments/79xgcg/disclosure_wordpress_wpdb_sql_injection_technical/dp7wln0/?context=5
For database drivers that support sending the query and parameters in the
same TCP packet (n.b. not in the same query string, though, or we lose the
code-data separation benefits that prepared statements offers and makes SQL
injection provably mitigated), we can make prepared statements as efficient
as unsafe queries.
My proposal, for one-off prepared queries:
$results = $pdo->safeQuery(
"SELECT * FROM foo WHERE id = :userid",
array('userid' => $_GET['user_id'])
);
In this case, $results will be a PDOStatement object just like if you
performed the following:
$results = $pdo->prepare("SELECT * FROM foo WHERE id = :userid");
$results->execute(['userid' => $_GET['user_id']);
However, it won't need a separate execute() call. You can immediately fetch
the results.
We use a similar interface in EasyDB[1], but this is a higher-level
abstraction around PDO::prepare() and PDOStatement::execute().
Questions/Challenges:
1. Which DB drivers (and which versions) support 1RT prepared statements in
addition to 2RT prepared statements?
2. Is there a better name for this usage than safeQuery()?
If this turns out to be a good idea, I'll write up an RFC targeting PHP 7.3.
-----
[1]: https://github.com/paragonie/easydb
Scott Arciszewski
Chief Development Officer
Paragon Initiative Enterprises <https://paragonie.com>