Как защититься от SQL инъекции при запросе в ContentResolver?

SQL-инъекция – вид атаки на сайты и приложения, основанный на внедрении вредоносного SQL-кода.

Например приложение предоставляет пользователю возможность найти контакт по имени. Для этого читается пользовательский ввод и выполняется запрос через ContentResolver. Такую логику можно реализовать следующим образом:

val projection = arrayOf("first_name", "last_name")
val selection = "first_name = ${searchEditText.getText()}"
val result = contentResolver.query("content://my_contacts/contacts", projection, selection, null, null)


Например пользователь вводит "Ivan", тогда выполняется SQL-запрос
SELECT first_name, last_name FROM content://my_contacts/contacts WHERE first_name = Ivan.


При такой реализации злоумышленник может ввести вредоносный SQL-код в поле поиска: nothing; DROP TABLE *;, что приведет к запросу
SELECT first_name, last_name FROM content://my_contacts/contacts WHERE first_name = nothing; DROP TABLE *;

Этот запрос удаляет все таблицы контент провайдера.

Чтобы защититься от SQL-инъекции, используется параметризованный selection. Для этого пишут "?" на месте параметров в строке selection и передают значения параметров в массиве selectionArgs:

val projection = arrayOf("first_name", "last_name")
val selection = "first_name = ?"
val selectionArgs = arrayOf(searchEditText.getText().toString())
val result = contentResolver.query("content://my_contacts/contacts", projection, selection, selectionArgs, null)


Аргументы selectionArgs экранируются перед выполнением SQL-запроса, поэтому описанная SQL-инъекция не сработает.