直奔主题,先看一个安全风险隐患整改通知:
被检测出风险的代码如下(通过机型过滤数据):
String sql="select * from behavior where device = '" + et_device.getText().toString() + "'";
Cursor rawQuery = sQLiteDatabase.rawQuery(sql, null);
产生原因:
query()中使用拼接字符串组成SQL语句的形式去查询数据库,那么为什么这样做就会有注入漏洞呢,以上面被检测到有风险的代码为例:
通常的情况,在编辑框里面输入的device是一个固定的型号,如“HUAWEI”,查询语句就是:
select * from behavior where device = 'HUAWEI',此时会获取到“HUAWEI”相关的数据。
如果有人故意输入 'HUAWEI' or '0=0',查询语句就变成了:select * from behavior where device = 'HUAWEI' or '0=0',此时会获取到数据库中的所有数据,攻击者使用输入的内容,导致数据库信息泄露,就称为数据库注入漏洞。
解决方案:
抽取出查询参数,使用占位符“?”代表了要输入的参数,使用字符串数组的形式将查询参数传入第二个参数作为selectionArgs的值。将代码修改为:
String sql ="select * from behavior where device = ?";
String[] selectionArgs =new String[]{et_device.getText().toString()};
Cursor rawQuery = sQLiteDatabase.rawQuery(sql, selectionArgs );
此方法是通过使用占位符?,代表我们要输入的参数。rawQuery函数中的第一个参数是sql语句,第二个参数替换掉占位符,所以即使故意输入故意输入 'HUAWEI' or '0=0',也会被视为一个整体,代表device,避免对查询语句产生影响。
如果有多个查询条件怎么处理呢,如device和version,正确写法为:
String sql= "select * from behavior where device =? and version=?";
String[] selectionArgs =new String[]{et_device.getText().toString(),et_version.getText().toString()};
Cursor rawQuery= sQLiteDatabase.rawQuery(sql,selectionArgs );
如果是多参数的Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy),应该怎么处理呢?
同样的道理,提取出参数,单独传入,先看风险写法:
String selection ="device = '" + et_device.getText().toString() + "'";
Cursor query= sQLiteDatabase.query(
"behavior",
null,
selection ,
null,null,null,null,null);
安全的写法:
String selection ="device = ?";
String[] selectionArgs =new String[]{et_device.getText().toString()}
Cursor query= sQLiteDatabase.query(
"behavior",
null,
selection,
selectionArgs,
null,null,null,null);
综上,养成规范书写SQL语句的习惯,不要使用动态拼装sql。