CXX.SQL.INJECT
SQL Injection from possible improper neutralization of special elements used in an SQL command
This checker flags SQL injection vulnerabilities. When a SQL statement is created by using unvalidated input, it is possible for a malicious user to inject a string and execute arbitrary SQL statements with the privileges of the attacked application on the database used by this application.
Vulnerability and risk
When input to code is not validated properly, an attacker can craft the input in a form that will allow the attacker to execute arbitrary SQL statements. With this sort of opportunity, an attacker could:
- read confidential data in the application's database
- modify data in the application's database
- execute arbitrary commands such as deleting all the information in the database
Mitigation and prevention
To avoid this issue, it is best to
- use only constant strings when creating SQL statement
- use safe libraries to create parameterized SQL statements that use inputs
- add validation code before using inputs in a SQL statement
Vulnerable code example 1
The following is an example containing a SQL injection vulnerability by using the SQLite C/C++ API.
void cwe_89_example_2(sqlite3 *database)
{
const char *userName;
const char *itemName;
char *sql;
gets(userName);
gets(itemName);
strcat(sql, "SELECT * FROM items WHERE owner = '");
strcat(sql, userName);
strcat(sql, "' AND itemname = '");
strcat(sql, itemName);
strcat(sql, "'");
char *errMsg = 0;
sqlite3_exec(database, sql, NULL, 0, &errMsg);
}
Klocwork produces a SQL injection report for line 14, indicating that an unsafe SQL query string has been used as a command. A SQL injection in this case could happen using the input `“name'; DELETE FROM items; --”` for `itemName`. This is due to not properly escaping reserved characters in SQL queries such as single-quote characters in the `itemName` string. In this case, assuming the user name is `'wiley'`, the sql string is parsed and executed as the following 3 statements:'
SELECT * FROM items WHERE owner = 'wiley' AND itemname = 'name'; DELETE FROM items; --'
The execution of the `DELETE` statement will delete all entries from the `'items'` table in the database.
Fixed code example 1
Constructing SQL queries by using unvalidated user input and not escaping reserved characters is dangerous. For this reason, you should use other functions from the SQLite C/C++ API for constructing a prepared statement object from the sql query, and binding user input to the parameters of the sql query, where proper handling of reserved characters is done. For example, you could construct a prepared statement object by using `sqlite3_prepare_v2` and bind the parameters of the query from the user input by using the `sqlite3_bind*` functions. This approach will correctly escape the reserved SQL query characters (for example, single-quote characters), which will prevent the construction and execution of the `"DELETE from items"` command. This can be done as follows:
void cwe_89_example_2_fixed(sqlite3 *database)
{
const char *userName;
const char *itemName;
const char *sql = "SELECT * FROM items WHERE owner = (?) AND itemname = (?)";
gets(userName);
gets(itemName);
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) != SQLITE_OK) {
printf("sqlite3_prepare_v2 failure: %s", sqlite3_errmsg(database));
return;
}
if (sqlite3_bind_text(statement, 1, userName, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
printf("sqlite_3_bind_text unable to bind argument 1: %s", sqlite3_errmsg(database));
sqlite3_finalize(statement);
return;
}
if (sqlite3_bind_text(statement, 2, itemName, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
printf("sqlite_3_bind_text unable to bind argument 2: %s", sqlite3_errmsg(database));
sqlite3_finalize(statement);
return;
}
if (sqlite3_step(statement) != SQLITE_DONE) {
printf("sqlite_3_step failure: %s", sqlite3_errmsg(database));
}
sqlite3_finalize(statement);
}
Related checkers
External guidance
Security training
Application security training materials provided by Secure Code Warrior.
Extension
This checker can be extended through the Klocwork knowledge base. See C/C++ knowledge base reference for more information.