2012-03-25 115 views
12

在Android中,android.database.sqlite.SQLiteStatement允許我在SQLite中使用預準備語句來避免注入攻擊。它的execute方法適用於創建/更新/刪除操作,但是對於返回遊標等的查詢似乎沒有任何方法。查詢與Android中的準備語句?

現在在iOS中,我可以創建類型爲sqlite3_stmt*的預準備語句並將它們用於查詢,所以我知道這不是SQLite的限制。我如何使用Android中的預準備語句執行查詢?

回答

39

準備好的語句可以做兩件事情

  • 加速性能,因爲數據庫不需要每次解析聲明
  • 綁定&逃生參數在聲明中讓你節省反對注入攻擊

我不知道確切位置/時,機器人會SQLite的實現實際上使用sqlite3_prepare(afiak不sqlite3_prepare_v2 - 見here),但我噸使用它,否則你不能得到Reached MAX size for compiled-sql statement cache errors

所以,如果你想查詢數據庫,你必須依賴於實現,我不知道用SQLiteStatement做到這一點。

關於注射安全性,每個數據庫查詢,插入等方法都有(有時候是可選的)版本,允許您綁定參數。

E.g.如果你想獲得一個Cursor

SELECT * FROM table WHERE column1='value1' OR column2='value2' 

Cursor SQLiteDatabase#rawQuery(

  • String sql,:全SELECT statment可以包括?到處
  • 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條款withouth的WHERE可/應包括?
  • String[] selectionArgs,:GROUP BY條款W/O GROUP BY
  • String having,:HAVING條款,替換?,爲了值出現
  • String groupBy,名單W/O HAVING
  • String orderByORDER BY子句的w/o ORDER BY

)

Cursor c2 = db.query("table", null, 
    "column1=? OR column2=?", 
     new String[] {"value1", "value2"}, 
     null, null, null); 

通過ContentProviders - 因爲你有一個抽象的提供商,而不是一個數據庫進行交互這種情況下略有不同。我們不保證有一個支持ContentProvider的sqlite數據庫。所以,除非你知道哪些列/哪些提供者在內部工作,你應該堅持文檔所說的。

Cursor ContentResolver#query(

  • Uri uri,:一個URI表示該數據源(內部轉換到一個表)
  • String[] projection,:所需的列的列表中,null = *
  • String selection,:WHERE子句withouth WHERE can/should include ?
  • String[] selectionArgs,:ORDER BY條款W/O ORDER BY

)

Cursor c3 = getContentResolver().query(
    Uri.parse("content://provider/table"), null, 
    "column=? OR column2=?", 
     new String[] {"value1", "value2"}, 
     null); 

提示:該更換?,以便它們出現

  • String sortOrder值的列表,如果你想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"); 
    

    在所有情況下?將通過你把在綁定參數中的轉義版本所取代。

    ? + "hack'me" = 'hack''me'

  • +1

    優秀帖子,謝謝你,幫了我很多。像這樣的時代讓我覺得我們需要能夠不止一次地改裝。 – Louis 2012-07-03 07:11:18

    +1

    即使這個答案很安靜,是否有一種解決方法來綁定除String以外的其他任何東西。我的查詢請求一個數值被綁定,但SqliteDatabase中的每個方法都使用一個String數組。如果我自己創建PreparedStatement,我可以執行查詢來恢復光標......我不相信沒有解決方案,但我一直沒有找到它。 – AxelH 2015-08-25 07:06:18

    +0

    @AxelH解決方法是,所有東西都可以用字符串表示。例如使用'String.valueOf(yourNumericThingHere)'。 – zapl 2015-08-25 07:27:41