Does SQLiteDatabase#rawQuery escape the selectionArgs (is it safe)? - android

Checking the rawQuery(sql, selectionArgs) docs, I don't see any explicit statement about selectionArgs escaping.
So should I sanitize the selectionArgs ahead, or is it safe to assume the rawQuery will use any selectionArgs values in safe way, avoiding SQL Injection?
I'm interested into Android API 14+ implementations, I don't care about any security bugs in old 1.x and 2.x ROMs.
(I'm not talking about the first String sql parameter, that one looks obviously vulnerable, but I would expect the args to be sanitized, yet there's no documentation about it on developer.android.com)

Selection args use sqlite's variable binding and they are never part of the SQL itself. No sanitization is needed.
The Android documentation is actually misleading here:
You may include ?s in where clause in the query, which will be replaced by the values from selectionArgs. The values will be bound as Strings.
The first sentence would indicate some sort of string replacement happening while there is no string replacement going on actually. The latter sentence refers to (variable) binding which is correct, and for which there's e.g. SQLiteProgram and its bindAllArgsAsStrings() between SQLiteDatabase and the sqlite C API.

Related

Why do we say id when reading something in SqLite, but 'id' when creating/updating/deleting a row?

I am creating a notes app. The user can input a note, and it will get saved to the database/displayed on the screen.
I have a DatabaseHelper class which includes all the CRUD methods(Create, Read, Update, Delete).
When I update a specific note in a table, I have to do it like this:
db.update("Note", contentValues, "id='"+id+"'", null)
with '' surrounding the user's id.
However, when I am querying to read a note, I don't have to include the '':
String fetchOneNote = "SELECT * FROM Note WHERE id="+id;
Is there a specific reason for this? It seems like in both, I am referring to the database, so why do I need the ''?
Thanks!
There is no need to enclose a numeric literal in single quotes but single quotes are required for a string literal.
So IF id is numeric there is no need to enclose it in single quotes. However, it doesn't hurt to enclose a numeric literal in quotes.
As such ASSUMING that id is numeric then:-
db.update("Note",contentValues,"id=" + id,null)
will effectively work the same as :-
db.update("Note", contentValues, "id='"+id+"'", null)
However, the recommended use of the SQLiteDatabase update method is to utilise the 4th parameter for the where clause parameters which protects against SQLite injection. As such it would be better to use :-
db.update("Note",contentValues,"id=?",new String[]{id});
The SQLite parser then handles the id appropriately, replacing the ? with the value and protects against SQLite injection.
See https://sqlite.org/lang_expr.html#literal_values_constants_ and also https://sqlite.org/lang_expr.html#parameters
Although the explanation regarding binding parameters includes:-
But because it is easy to miscount the question marks, the use of this parameter format is discouraged. Programmers are encouraged to use one of the symbolic formats below or the ?NNN format above instead.
The ? is commonly used. This is what the update method (and other methods) expect.
It does mean that on occasions you may have to code the same parameterised (bound) parameter twice along with ?'s (as you would if not using bound parameters).

Android SQLite update - why whereargs?

The Android SDK documentation for SQLite provides an update method which takes as its parameters four values - table, values, whereClause, whereArgs. The first three make complete sense. However, it is not clear to me that using whereArgs with a whereClause containing ?'s as opposed to sending out a fully prepared whereClause offers any benefits - either in terms of security (there is no suggestion that this somehow helps to sanitize the SQL) or speed. So what then are the benefifts of going down that route instead of simply passing a full where string and a null whereArgs?
The docs say:
String: You may include ?s in the where clause, which will be replaced by the values from whereArgs. The values will be bound as Strings.
This is slightly misleading. No "replacement" takes place actually. Instead the ?s are variables and the whereArgs are values that are bound to those variables, and this binding happens inside the sqlite SQL program.
Using variable binding avoids issues such as SQL injection without the need to sanitize inputs.
Similar mechanism would be beneficial for performance in case you were executing the same SQL program over and over again with different values for variables. You only need to compile the SQL once. Android SQLite mechanism for that is SQLiteStatement (see the bind...() methods in its SQLiteProgram superclass).
Security is definitely an issue. If you use string concatenation, you are vulnerable to SQL Injection. Using ? and whereArgs does indeed sanitize the input so you are safe.
There is also the case of prepared statements - you compile them only once and then bind different values for each arguments placeholder. This will give you a benefit in terms of performance. You can't get that with your approach.

Improper Neutralization of Special Elements used in an SQL Command

My App data managed by the Content Provider using CursorLoaders is in SQLite database.
According to Veracode Static Scan report , it is prone to SQL Injections.
But according to docs,
To avoid this problem, use a selection clause that uses ? as a replaceable parameter and a separate array of selection arguments. When you do this, the user input is bound directly to the query rather than being interpreted as part of an SQL statement. Because it's not treated as SQL, the user input can't inject malicious SQL.
public Loader<Cursor> onCreateLoader(int id, Bundle b) {
return new CursorLoader(getActivity(),
NewsFeedTable.CONTENT_URI,
NewsFeedTable.PROJECTION,
"_id = ?",
new String[]{tid},
null);
}
As shown in above code, I am doing in similar way.
Also I read same in The Mobile Application Hacker's Book
If this is not sufficient measure to prevent SQL injections, how do I sanitize the sql query from the special characters?
Every read suggests using parameterized PreparedStatements.
Is it not default with Content Providers?
An alternative to SQLiteStatement is to use the query, insert, update, and delete methods on SQLiteDatabase as they offer parameterized statements via their use of string arrays.
I found this as a solution :
But then I read docs from here that
StringEscapeUtils.escapeSql
This was a misleading method, only handling the simplest of possible SQL cases. As SQL is not Lang's focus, it didn't make sense to maintain this method.
Adding the code snippet. Report points at Line 307 where SQL Injection flaw is detected:
How should I do input validation for the special characters?
Please help, to make me understand it better.
Values in selectionArgs parameters do not need to be escaped, and they must not be escaped because the escape characters would end up in the database.
There are three different cases of SQL code seen by Veracode:
values that cannot be user input (such as string literals in the source code);
values that are user input (because the come directly from, e.g., some edit box);
values that might be user input, because the tool cannot determine the source.
For marketing reasons, paid-for tools tend to inflate the problem numbers as much as possible. So Veracode reports all instances of the third case as problems.
In this case, Veracode does not know where selection comes from, so it complains. If that value is constructed by your program and never contains any user input (i.e., all user-input values are moved to ? parameters), then this is a false positive, and you must tell Veracode to shut up.

Why do some SQLite methods expect arguments as an Object[] while others need a String[]?

I'm curious about the design of the Android SQLite API. For example, we have
public void execSQL(String sql, Object[] bindArgs)
for SQLs that don't return data, and we also have
public Cursor rawQuery(String sql, String[] selectionArgs)
for SQLs that do return data.
Why are the arguments expected as an Object array in the former and as a String array in the latter case? I understand that accepting only Strings might make sense due to SQLite's type affinity. However, if that is the case, why not consistently use String arrays for arguments? Is there some non-String argument that makes sense for execSQL but not for rawQuery?
Actually, accepting only strings does not make sense because strings never compare equal with numbers, i.e., queries like
c.rawQuery("SELECT * FROM mytable WHERE some_number_column = ?", args);
will never return any records with numbers. (You would have to declare all columns as TEXT, and never use expressions or convert them with something like CAST(... AS TEXT).)
Jens mentioned a possible explanation, but that is no excuse for inconsistent and plain bad design.
There is one. For example if you want to compare BLOB values. Have a look at this example.
UUID stored as BLOB
db.execSQL("DELETE FROM "+USER_TABLE+" WHERE "+USER_UUID+"=?",
new Object [] { uuid.toByteArray }
According to documentation, byte[], String, Long and Double are supported in bindArgs. However, it is not recommended to use this method for executing SELECT/INSERT/UPDATE/DELETE statements.
I just don't know why.

Create cursor from SQLiteStatement

I would like to use SQLiteStatement in my ContentProvider instead of the rawQuery or one of the other standard methods. I think using SQLiteStatement would give a more natural, native, efficient and less error prone approach to doing queries.
The problem is that I don't see a way to generate and return a Cursor. I realize I can use "call" and return a Bundle, but that approach requires that I cache and return all selected rows at the same time - this could be huge.
I will start looking at Android source code - I presume that "query" ultimately uses SQLiteStatement and somehow generates a Cursor. However, if anyone has any pointers or knowledge of this, I would greatly appreciate your sharing.
I would like to use SQLiteStatement in my ContentProvider instead of the rawQuery or one of the other standard methods. I think using SQLiteStatement would give a more natural, native, efficient and less error prone approach to doing queries.
Quoting the documentation for SQLiteStatement:
The statement cannot return multiple rows or columns, but single value (1 x 1) result sets are supported.
I fail to see why you would bother with a ContentProvider for single row, single column results, but, hey, it's your app...
The problem is that I don't see a way to generate and return a Cursor
Create a MatrixCursor and fill in the single result.

Categories

Resources