如何使用 SQLite 中的预准备语句为 Android 应用程序编写 INSERT、UPDATE、DELETE、SELECT、嵌套 SELECT 命令?

How to write INSERT, UPDATE, DELETE,SELECT,Nested SELECT command using a prepared statement in SQLite for Android Application?

最近我了解到 android 中的原始查询无法防止 SQL 注入,因此我决定将 Prepared 语句中的所有查询转换为 SQL 注入预防。但是我不知道如何在Prepared Statement中转换复杂的查询。

我想转换以下查询:

1.

select
    *
FROM
    TableName
where
    (tab1col1 in(SELECT tab2Col2 FROM MasterTable where tab2col1='Y')
    or  tab1col2 = CV.TRUE)
order by
    tab1col3, tab1col4, tab1col5,tab1col6

2.

Select
    * ,count(*) as TOTAL_COUNT ,
    SUM(CASE WHEN tabCol1 LIKE '%todayDate%' THEN 1 ELSE  0 END) as  TOTAL_COL1_COUNT
from
    TableName
group by tabCol2;

防止SQL注入的唯一方法是使用参数。 (在某些 PHP API 中,获取参数的唯一方法是使用准备好的语句,但这不是 Android 数据库 API 中的缺点之一。)

任意字符串写?,分别传值:

String name = ...;
String password = ...;
cursor = db.rawQuery("SELECT SomeCol FROM Users WHERE Name = ? AND Password = ?",
                     new String[]{ name, password });

请注意,只有当您拥有由(潜在敌对的)用户控制的字符串值时,才会发生 SQL 注入。您上面的查询看起来不像是这种情况。

您可以使用 rawQuery 通过 selectionargs(第二个参数)传递任何参数来防止注入。

SQL 注入,不适用于任何一个查询,因为它们是硬编码的并且没有用户 generated/supplied 输入。

例如您的第一个查询可能是(假设 'Y' 和 CV.TRUE 作为参数传递(即用户 generated/supplied)为了演示):-

public Cursor query1raw(String indicator1,String indicator2) {
    String sql = "SELECT * " +

            " FROM TableName " +
            " WHERE (tab1col1" +
            "     IN(" +
            "         SELECT tab2col2 " +
            "         FROM MasterTable " +
            "         WHERE tab2col1=?)" +
            "     OR  tab1col2=?)" +
            " ORDER BY tab1col3, tab1col4,tab1col5,tab1col6";
    String[] args = new String[]{indicator1,indicator2};
    return mDB.rawQuery(sql,args);
}

但是,通常建议使用方便的方法而不是 rawQueryexecSQL,当它们可以使用时,再次通过参数使用绑定字符串,上面,使用 query 方便方法可以是:-

public Cursor query1(String indicator1, String indicator2) {
    String whereclause = "(tab1col1 IN(SELECT tab2col2 FROM MasterTable WHERE tab2col1=?) OR tab1col2=?)";
    String[] whereargs = new String[] {indicator1,indicator2};
    String order_columns = "tab1col3,tab1col4,tab1col5,tab1col6";
    return mDB.query("TableName",null,whereclause,whereargs,null,null,order_columns);
}

您不会自己使用准备好的语句,因为它们仅限于返回单个值,而不是一行或多列的行。


不建议警告

但是,如果你真的想要,你可以使用 :-

public Cursor query1ps(String indicator1,String indicator2) {
    String[] whereargs = new String[] {indicator1,indicator2};
    SQLiteStatement stmnt = mDB.compileStatement("SELECT * " +
            " FROM TableName " +
            " WHERE (tab1col1" +
            "     IN(" +
            "         SELECT tab2col2 " +
            "         FROM MasterTable " +
            "         WHERE tab2col1=?)" +
            "     OR  tab1col2=?)" +
            " ORDER BY tab1col3, tab1col4,tab1col5,tab1col6");
    stmnt.bindAllArgsAsStrings(whereargs);
    Log.d("PREPAREDSQL",stmnt.toString());
    String sql = stmnt.toString().replace("SQLiteProgram:","");
    return mDB.rawQuery(sql,null);
}
  • 如您所见,所有准备好的语句都是这样做的,正在替换参数,因此与其他方法相比没有什么好处。这也取决于 SQLIteProgram: 保持不变。