Запросы с подготовленными высказываниями в 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'

Другие вопросы по тегам