【问题标题】:Queries with prepared statements in Android?在 Android 中使用准备好的语句进行查询?
【发布时间】:2012-04-09 01:38:00
【问题描述】:

在 Android 中,android.database.sqlite.SQLiteStatement 允许我在 SQLite 中使用准备好的语句来避免注入攻击。它的execute 方法适用于创建/更新/删除操作,但是对于返回游标之类的查询似乎没有任何方法。

现在在 iOS 中,我可以创建 sqlite3_stmt* 类型的准备好的语句并将它们用于查询,所以我知道这不是 SQLite 的限制。如何在 Android 中使用准备好的语句执行查询?

【问题讨论】:

    标签: android sql sqlite prepared-statement


    【解决方案1】:

    准备好的语句允许你做两件事

    • 提高性能,因为数据库不需要每次都解析语句
    • 在语句中绑定和转义参数,这样可以避免注入攻击

    我不确切知道 Android 的 SQLite 实现在何处/何时实际使用 sqlite3_prepare(afiak 不是 sqlite3_prepare_v2 - 请参阅 here),但它确实使用了它,否则您无法获得 Reached MAX size for compiled-sql statement cache errors

    因此,如果您想查询数据库,您必须依赖实现,我不知道使用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 子句 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 子句没有 WHERE 可以/应该包括 ?
    • String[] selectionArgs, :替换 ? 的值列表,按它们出现的顺序排列
    • String sortOrder : ORDER BY 子句 w/o 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");
    

    在所有情况下,? 都将替换为您在绑定参数中输入的转义版本。

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

    【讨论】:

    • 出色的帖子,谢谢,对我帮助很大。像这样的时代让我觉得我们需要能够多次修改。
    • 即使这个答案很老,是否有一种解决方法可以绑定除字符串之外的任何内容。我的查询请求绑定一个数值,但 SqliteDatabase 中的每个方法都使用一个字符串数组。如果我自己创建 PreparedStatement,我可以执行查询来恢复光标...我不敢相信没有解决方案,但我还没有找到它。
    • @AxelH 解决办法是一切都可以用字符串表示。例如使用String.valueOf(yourNumericThingHere)
    • 当然可以,但是我的查询要求进行数值比较示例“columnX
    • 使用带有 whereClause 'columnX
    猜你喜欢
    • 2018-08-11
    • 2011-05-02
    • 1970-01-01
    • 1970-01-01
    • 2013-08-02
    • 2020-05-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多