Запросы с подготовленными высказываниями в Android?
В Android android.database.sqlite.SQLiteStatement
позволяет мне использовать подготовленные операторы в SQLite, чтобы избежать инъекционных атак. это execute
Метод подходит для операций создания / обновления / удаления, но, похоже, нет никакого метода для запросов, которые возвращают курсор или тому подобное.
Теперь в iOS я могу создавать готовые операторы типа sqlite3_stmt*
и использовать их для запросов, поэтому я знаю, что это не ограничение SQLite. Как я могу выполнять запросы с подготовленными заявлениями в Android?
1 ответ
Подготовленное утверждение позволяет сделать две вещи
- повысить производительность, поскольку базе данных не нужно каждый раз анализировать оператор
- связывайте и экранируйте аргументы в выражении, чтобы вы были защищены от атак инъекций
Я не знаю точно, где и когда реализация Androidite SQLite фактически использует sqlite3_prepare
(афиак нет sqlite3_prepare_v2
- смотрите здесь), но он использует его, в противном случае вы не сможете получить размер Reached MAX для ошибок кэша скомпилированных операторов SQL.
Поэтому, если вы хотите сделать запрос к базе данных, вы должны полагаться на реализацию, я не знаю, как это сделать. SQLiteStatement
,
Что касается безопасности внедрения, каждый запрос к базе данных, метод вставки и т. Д. Имеют (иногда альтернативные) версии, которые позволяют связывать аргументы.
Например, если вы хотите получить Cursor
снаружи
SELECT * FROM table WHERE column1='value1' OR column2='value2'
Cursor SQLiteDatabase#rawQuery(
String sql
,: полныйSELECT
устав, который может включать в себя?
вездеString[] selectionArgs
: список значений, которые заменяют?
в порядке их появления
)
Cursor c1 = db.rawQuery(
"SELECT * FROM table WHERE column1=? OR column2=?",
new String[] {"value1", "value2"}
);
Cursor SQLiteDatabase#query (
String table
,: имя таблицы, может включатьJOIN
так далееString[] columns
,: список необходимых столбцов,null
знак равно*
String selection
,:WHERE
пункт безWHERE
может / должен включать?
String[] selectionArgs
,: список значений, которые заменяют?
в порядке их появленияString groupBy
,:GROUP BY
пункт безGROUP BY
String having
,:HAVING
пункт безHAVING
String orderBy
:ORDER BY
пункт безORDER BY
)
Cursor c2 = db.query("table", null,
"column1=? OR column2=?",
new String[] {"value1", "value2"},
null, null, null);
Через ContentProviders - этот случай немного отличается, поскольку вы взаимодействуете с абстрактным поставщиком, а не с базой данных. На самом деле нет никакой гарантии, что база данных sqlite поддерживает ContentProvider
, Поэтому, если вы не знаете, какие есть столбцы / как работает поставщик, вам следует придерживаться того, что говорится в документации.
Cursor ContentResolver#query(
Uri uri
,: URI, представляющий источник данных (внутренне переведенный в таблицу)String[] projection
,: список необходимых столбцов,null
знак равно*
String selection
,:WHERE
пункт безWHERE
может / должен включать?
String[] selectionArgs
,: список значений, которые заменяют?
в порядке их появленияString sortOrder
:ORDER BY
пункт безORDER BY
)
Cursor c3 = getContentResolver().query(
Uri.parse("content://provider/table"), null,
"column=? OR column2=?",
new String[] {"value1", "value2"},
null);
Подсказка: если вы хотите LIMIT
здесь вы можете добавить его в ORDER BY
пункт:
String sortOrder = "somecolumn LIMIT 5";
или в зависимости от реализации ContentProvider
добавить его в качестве параметра к Uri
:
Uri.parse("content://provider/table?limit=5");
// or better via buildUpon()
Uri audio = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
audio.buildUpon().appendQueryParameter("limit", "5");
Во всех случаях ?
будет заменена экранированной версией того, что вы указали в аргументе bind.
?
+ "hack'me"
знак равно 'hack''me'