问题
I am referring to this answer of mine to another question, which another user criticized because vulnerable to SQL injection, even if no user input is requested and escape procedure is called. The following code is used to create a .sql dump of an SQLite database, using only PHP code with no call to sqlite3 tool (which was the original request of the author of the question).
<?php
$db = new SQLite3(dirname(__FILE__)."/your/db.sqlite");
$db->busyTimeout(5000);
$sql="";
$tables=$db->query("SELECT name FROM sqlite_master WHERE type ='table' AND name NOT LIKE 'sqlite_%';");
while ($table=$tables->fetchArray(SQLITE3_NUM)) {
$sql.=$db->querySingle("SELECT sql FROM sqlite_master WHERE name = '{$table[0]}'").";\n\n";
$rows=$db->query("SELECT * FROM {$table[0]}");
$sql.="INSERT INTO {$table[0]} (";
$columns=$db->query("PRAGMA table_info({$table[0]})");
$fieldnames=array();
while ($column=$columns->fetchArray(SQLITE3_ASSOC)) {
$fieldnames[]=$column["name"];
}
$sql.=implode(",",$fieldnames).") VALUES";
while ($row=$rows->fetchArray(SQLITE3_ASSOC)) {
foreach ($row as $k=>$v) {
$row[$k]="'".SQLite3::escapeString($v)."'";
}
$sql.="\n(".implode(",",$row)."),";
}
$sql=rtrim($sql,",").";\n\n";
}
file_put_contents("sqlitedump.sql",$sql);
In the comments to this answer, user @Dharman insisted this code is vulnerable, and after asking to provide a full example of a case of how it could lead to problems, he told me to just open a question regarding the matter.
I personally feel there is no way this code could "explode" because of the contents already present inside the database to be dumped, but I'm no authority. So I ask you instead.
回答1:
It's pretty reasonable to name a table Order in an e-commerce application, but this causes a syntax error if you run a query like:
SELECT * FROM Order
Why? Because Order is a reserved keyword in SQLite. It introduces an ORDER BY clause. Using a table named Order in this way just creates a syntax error.
SQLite allows you to name tables after reserved words by delimiting the table name.
This is in the documentation I linked to about reserved words:
'keyword' A keyword in single quotes is a string literal.
"keyword" A keyword in double-quotes is an identifier.
[keyword] A keyword enclosed in square brackets is an identifier. This is not standard SQL. This quoting mechanism is used by MS Access and SQL Server and is included in SQLite for compatibility.
`keyword` A keyword enclosed in grave accents (ASCII code 96) is an identifier. This is not standard SQL. This quoting mechanism is used by MySQL and is included in SQLite for compatibility.
So you can use a table named Order without error like this:
SELECT * FROM "Order"
You shouldn't use SQLite3::escapeString($table[0]) because that's for string literals. Remember from the list above, single-quoted strings are string literals. The escapeString() function only escapes ' characters, so you can put that string inside single-quotes as the delimiter, and thus you can use strings like 'O\'Reilly'.
But escapeString() doesn't do anything for the double-quotes used for delimiting table names. There isn't a function provided for that. So you either have to be sure you have no table names that contain a " character, or else use other PHP functions to escape them.
$safeTable = str_replace('"', '\\"', $table[0]);
$rows = $db->query("SELECT * FROM \"{$safeTable}\"");
You should also read 8. Double-quoted String Literals Are Accepted on this page: https://www.sqlite.org/quirks.html
来源:https://stackoverflow.com/questions/58225998/vulnerability-to-sql-injection-even-when-sqlite3escapestring-is-used-and-no