问题
I want to make query like this one:
SELECT lyrics FROM cache WHERE author=%s0, title=%s1 LIMIT 1;
where strings %s0
and %s1
should be substituted. Assuming strings are not sanitized, UTF-8 encoded (As database itself), simple null-terminated char*
arrays. What are my options to do this? Are there any built-in functions in SQLite (C API) for this?
回答1:
Like mentioned in comments already prepared statements should be used.
Why Prepared Statements Should Be Favoured
When you create SQL queries yourself as a string, they almost always contain parts of a user's input. An attacker can take advantage of this by, for example, cleverly changing the semantics of the query using '
and thus gaining unauthorized access to data or destroying data.
This is called SQL injection and is one of the top most critical security risks, see here: https://www.owasp.org/images/7/72/OWASP_Top_10-2017_%28en%29.pdf.pdf
Defense
The use of prepared statements with variable binding (aka parameterized queries) is how all developers should first be taught how to write database queries.
https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html#defense-option-1-prepared-statements-with-parameterized-queries
How to use prepared statements with SQLite
For prepared statements see https://www.sqlite.org/c3ref/stmt.html.
Basic steps are:
- create the prepared statement
- bind values to parameters
- run the SQL
- destroy the object to avoid resource leaks
Example
#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"
void exit_with_error(sqlite3 *db, const char * msg) {
fprintf(stderr, "%s: %s\n", msg, sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
int main() {
sqlite3 *db;
sqlite3_stmt *stmt;
int rc = sqlite3_open("path-to-lyrics", &db);
if (rc != SQLITE_OK)
exit_with_error(db, "can't open db: ");
//create prepared statement
rc = sqlite3_prepare_v2(db, "SELECT lyrics FROM cache WHERE author=?1 AND title=?2 LIMIT 1;", -1, &stmt, 0);
if (rc != SQLITE_OK)
exit_with_error(db, "failure fetching data: ");
//bind values to parameters
sqlite3_bind_text(stmt, 1, "Don Brownrigg", -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, "Just Breathe", -1, SQLITE_STATIC);
//run the SQL
rc = sqlite3_step(stmt);
if (rc == SQLITE_ROW) {
printf("%s\n", sqlite3_column_text(stmt, 0));
}
//destroy the object to avoid resource leaks
sqlite3_finalize(stmt);
sqlite3_close(db);
return 0;
}
Build
With CMake it could look like this:
cmake_minimum_required(VERSION 3.14)
project(sqlitequery C)
set(CMAKE_C_STANDARD 99)
add_executable(sqlitequery main.c)
target_link_libraries (sqlitequery sqlite3)
On command line one could build with something like:
gcc -Wall -Wextra main.c -lsqlite3 -o sqlitequery
来源:https://stackoverflow.com/questions/57505263/how-to-make-sqlite-select-query-in-c-correctly