Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >安卓应用安全指南 4.5.3 使用 SQLite 高级话题

安卓应用安全指南 4.5.3 使用 SQLite 高级话题

作者头像
ApacheCN_飞龙
发布于 2022-12-01 11:58:41
发布于 2022-12-01 11:58:41
72500
代码可运行
举报
文章被收录于专栏:信数据得永生信数据得永生
运行总次数:0
代码可运行

安卓应用安全指南 4.5.3 使用 SQLite 高级话题

原书:Android Application Secure Design/Secure Coding Guidebook 译者:飞龙 协议:CC BY-NC-SA 4.0

4.5.3.1 在 SQL 语句的LIKE断言中使用通配符时,应该实现转义过程

当所使用的字符串包含LIKE断言的通配符(%_),作为占位符的输入值时,除非处理正确,否则它将用作通配符,因此必须根据需要事先转义处理。 通配符应该用作单个字符(%_)时,需要转义处理。

根据下面的示例代码,使用ESCAPE子句执行实际的转义过程。

使用LIKE情况下的ESCAPE过程:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//Data search task
public class DataSearchTask extends AsyncTask<String, Void, Cursor> {

    private MainActivity mActivity;
    private SQLiteDatabase mSampleDB;
    private ProgressDialog mProgressDialog;

    public DataSearchTask(SQLiteDatabase db, MainActivity activity) {
        mSampleDB = db;
        mActivity = activity;
    }

    @Override
    protected Cursor doInBackground(String... params) {
        String idno = params[0];
        String name = params[1];
        String info = params[2];
        String cols[] = {"_id", "idno","name","info"};
        Cursor cur;

        [...]

        //Execute like search(partly match) with the condition of info
        //Point:Escape process should be performed on characters which is applied to wild card
        String argString = info.replaceAll("@", "@@"); // Escape $ in info which was received as input
        argString = argString.replaceAll("%", "@%"); // Escape % in info which was received as input
        argString = argString.replaceAll("_", "@_"); // Escape _ in info which was received as input
        String selectionArgs[] = {argString};
        try {
            //Point:Use place holder
            cur = mSampleDB.query("SampleTable", cols, "info LIKE '%' || ? || '%' ESCAPE '@'", selectionArgs, null, null, null);
        } catch (SQLException e) {
            Toast.makeText(mActivity, R.string.SERCHING_ERROR_MESSAGE, Toast.LENGTH_LONG).show();
            return null;
        }
        return cur;
    }

    @Override
    protected void onPostExecute(Cursor resultCur) {
        mProgressDialog.dismiss();
        mActivity.updateCursor(resultCur);
    }
}
4.5.3.2 不能用占位符时,在 SQL 命令中使用外部输入

当执行 SQL 语句,并且过程目标是 DB 对象,如表的创建/删除时,占位符不能用于表名的值。 基本上,数据库不应该使用外部输入的任意字符串来设计,以防占位符不能用于该值。

当由于规范或特性的限制,而无法使用占位符时,无论输入值是否危险,都应在执行前进行验证,并且需要执行必要的过程。

基本上,应该执行:

  1. 使用字符串参数时,应该对于字符进行转义或引用处理。
  2. 使用数字值参数时,请确认不包含数值以外的字符。
  3. 用作标识符或命令时,请验证是否包含不能使用的字符以及(1)。

参考:http://www.ipa.go.jp/security/vuln/documents/website_security_sql.pdf (日文)

4.5.3.3 采取数据库非预期覆盖的对策

通过SQLiteOpenHelper#getReadableDatabasegetWriteableDatabase获取数据库实例时,通过使用任一方法 [14],DB 将以可读/可写状态打开。 另外,与Context#openOrCreateDatabaseSQLiteDatabase#openOrCreateDatabase相同。这意味着 DB 的内容可能会被应用操作,或实现中的缺陷意外覆盖。 基本上,它可以由应用规范和实现范围来支持,但是当实现仅需要读取功能的功能(如应用的搜索功能等)时,通过只读方式打开数据库,可能会简化设计或检查,从而提高应用质量,因此建议视情况而定。

[14] getReableDatabase()getWritableDatabase可能返回同一个对象。 它的规范是,如果可写对象由于磁盘满了而无法生成,它将返回只读对象。 (getWritableDatabase()会在磁盘满了的情况下产生错误)

特别是,通过对SQLiteDatabase#openDatabase指定OPEN_READONLY打开数据库。

以只读打开数据库:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[...]
// Open DB(DB should be created in advance)
SQLiteDatabase db
    = SQLiteDatabase.openDatabase(SQLiteDatabase.getDatabasePath("Sample.db"), null, OPEN_READONLY);

参考:http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#getReadableDatabase()

4.5.3.4 根据应用需求,验证 DB 的输入输出数据的有效性

SQLite 是类型容错的数据库,它可以将字符类型数据存储到在 DB 中声明为整数的列中。 对于数据库中的数据,包括数值类型的所有数据都作为纯文本的字符数据存储在数据库中。 所以搜索字符串类型,可以对整数类型的列执行(LIKE '%123%'等)。此外,由于在某些情况下,可以输入超过限制的数据,所以对 SQLite 中的值(有效性验证)的限制是不可信的,例如VARCHAR(100)

因此,使用 SQLite 的应用需要非常小心 DB 的这种特性,并且有必要根据应用需求采取措施,不要将意外的数据存储到数据库,或不要获取意外的数据。 对策是以下两点。

  1. 在数据库中存储数据时,请确认类型和长度是否匹配。
  2. 从数据库中获取值时,验证数据是否超出假定的类型和长度。

下面是个代码示例,它验证了输入值是否大于 1。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MainActivity extends Activity {

    [...]

    //Process for adding
    private void addUserData(String idno, String name, String info) {
        //Check for No
        if (!validateNo(idno, CommonData.REQUEST_NEW)) {
            return;
        }
        //Inserting data process
        DataInsertTask task = new DataInsertTask(mSampleDbyhis);
        task.execute(idno, name, info);
    }

    [...]

    private boolean validateNo(String idno, int request) {
        if (idno == null || idno.length() == 0) {
            if (request == CommonData.REQUEST_SEARCH) {
                //When search process, unspecified is considered as OK.
                return true;
            } else {
                //Other than search process, null and blank are error.
                Toast.makeText(this, R.string.IDNO_EMPTY_MESSAGE, Toast.LENGTH_LONG).show();
                return false;
            }
        }
        //Verify that it's numeric character
        try {
            // Value which is more than 1
            if (!idno.matches("[1-9][0-9]*")) {
                //In case of not numeric character, error
                Toast.makeText(this, R.string.IDNO_NOT_NUMERIC_MESSAGE, Toast.LENGTH_LONG).show();
                return false;
            }
        } catch (NullPointerException e) {
            //It never happen in this case
            return false;
        }
        return true;
    }

    [...]
}
4.5.3.5 考虑 – 储存在数据库中的数据

在 SQLite 视线中,将数据储存到文件是这样:

  • 所有包含数值类型的数据,都将作为纯文本的字符数据存储在 DB 文件中。
  • 执行 DB 的数据删除时,数据本身不会从 DB 文件中删除。 (只添加删除标记。)
  • 更新数据时,更新前的数据未被删除,仍保留在数据库文件中。

因此,“必须”删除的信息仍可能保留在 DB 文件中。 即使在这种情况下,也要根据本指导手册采取对策,并且启用 Android 安全功能时,数据/文件可能不会被第三方直接访问,包括其他应用。 但考虑到通过绕过 Android 的保护系统(如 root 权限)选取文件的情况,如果存储了对业务有巨大影响的数据,则应考虑不依赖于 Android 保护系统的数据保护

由于上述原因,需要保护的重要数据,不应该存储在 SQLite 数据库中,即使设备取得了 root 权限。 在需要存储重要数据的情况下,有必要采取对策或加密整个数据库。

当需要加密时,有许多问题超出了本指南的范围,比如处理用于加密或代码混淆的密钥,所以目前建议,在开发处理数据的应用,数据对业务有巨大影响时咨询专家。 请参考“4.5.3.6 [参考] 加密 SQLite 数据库(Android SQLCipher)”,这里介绍加密数据库的库。

4.5.3.6 [参考] 加密 SQLite 数据库(Android SQLCipher

SQLCipher是为数据库提供透明 256 位 AES 加密的 SQLite 扩展。 它是开源的(BSD 许可证),由 Zetetic LLC 维护/管理。 在移动世界中,SQLCipher广泛用于诺基亚/ QT,苹果的 iOS

Android 项目的SQLCipher旨在支持 Android 环境中的 SQLite 数据库的标准集成加密。 通过为SQLCipher创建标准 SQLite 的 API,开发人员可以使用加密的数据库和平常一样的编码。

参考:https://guardianproject.info/code/sqlcipher/

如何使用:

应用开发者可以通过以下三个步骤使用SQLCipher

  1. 在应用的lib目录中找到sqlcipher.jarlibdatabase_sqlcipher.solibsqlcipher_android.solibstlport_shared.so
  2. 对于所有源文件,将所有android.database.sqlite.*更改为info.guardianproject.database.sqlite.*,它们由import指定。另外,android.database.Cursor可以照原样使用。
  3. onCreate()中初始化数据库,打开数据库时设置密码。

简单的代码示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SQLiteDatabase.loadLibs(this); // First, Initialize library by using context.
SQLiteOpenHelper.getWRITEABLEDatabase(passwoed): // Parameter is password(Suppose that it's string type and It's got in a secure way.)

在撰写本文时,Android 版SQLCipher是 1.1.0 版,现在正在开发 2.0.0 版,现在已经公布了 RC4。 就过去在 Android 中的使用和 API 的稳定性而言,有必要稍后进行验证,但目前还可以看做 SQLite 的加密解决方案,它可以在 Android 中使用。

库的结构

下列 SDK 中包含的文件是使用SQLCipher所必须的。

  • assets/icudt46l.zip 2,252KB

icudt46l.dat不存在于/system/usr/icu/下及其早期版本时,这是必需的。 当找不到icudt46l.dat时,此 zip 需要解压缩并使用。

  • libs/armeabi/libdatabase_sqlcipher.so 44KB
  • libs/armeabi/libsqlcipher_android.so 1,117KB
  • libs/armeabi/libstlport_shared.so 555KB

本地库,它在SQLCipher首次加载(调用SQLiteDatabase#loadLibs())时被读取。

  • libs/commons-codec.jar 46KB
  • libs/guava-r09.jar 1,116KB
  • libs/sqlcipher.jar 102KB

Java 库调用本地库。sqlcipher.jar是主要的,其它的由sqlcipher.jar引用。

总共大约 5.12MB。但是,当icudt46l.zip解压时,总共大约 7MB。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-03-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
安卓应用安全指南 4.5.1 使用 SQLite 示例代码
在 Android 应用中处理数据库时,可以通过使用SQLiteOpenHelper [10] 来实现数据库文件的适当安排和访问权限设置(拒绝其他应用访问的设置)。 下面是一个简单的应用示例,它在启动时创建数据库,并通过 UI 执行搜索/添加/更改/删除数据。 示例代码完成了 SQL 注入的防范,来避免来自外部的输入执行不正确的 SQL。
ApacheCN_飞龙
2022/12/01
3580
安卓应用安全指南 4.5.2 使用 SQLite 规则书
考虑到 DB 文件数据的保护,DB 文件位置和访问权限设置是需要一起考虑的非常重要的因素。 例如,即使正确设置了文件访问权,如果 DB 文件位于无法设置访问权的位置,则任何人可以访问 DB 文件,例如, SD 卡。 如果它位于应用目录中,如果访问权限设置不正确,它最终将允许意外访问。 以下是正确分配和访问权限设置的一些要点,以及实现它们的方法。 为了保护数据库文件(数据),对于位置和访问权限设置,需要执行以下两点。
ApacheCN_飞龙
2022/12/01
7970
数据存储之-SQLite数据库一
对于涉及数据库的app,我们不可能手动地去给他创建数据库文件,所以需要在第一次启用app 的时候就创建好数据库表;而当我们的应用进行升级需要修改数据库表的结构时,这个时候就需要 对数据库表进行更新了;对于这两个操作,安卓给我们提供了SQLiteOpenHelper的两个方法, onCreate( )与onUpgrade( )来实现
小小工匠
2021/08/16
6780
Android SQLite数据库基本用法详解
public class DBHelper extends SQLiteOpenHelper{
奶油话梅糖
2021/03/16
2.2K0
Android学习--持久化(三) SQLite & LitePal
    自己做为一个iOS开发,看到安卓这一块的时候,那中浓烈的熟悉味道更加强烈,SQLite这种轻量级的关系型数据库的使用在移动端相差不多,iOS有FMDB,Android有LitePal, 这一篇文章好好总结一下 SQLite & LitePal,由于自己用的是Mac系统,在配置 adb的时候也遇到了一些问题,把这些问题也都说一下,避免大家跳太多的坑吧。这个我们就先说说在Mac系统下配置这个adb,因为这个不管是我们使用原生SQLite还是用LitePal,这东西都是必须的,说以先说说它的一个配置:
Mr.RisingSun
2018/07/31
8030
Android学习--持久化(三) SQLite & LitePal
【Android 应用开发】Android 数据存储 之 SQLite数据库详解
转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/19028665
韩曙亮
2023/03/27
2.5K0
【Android 应用开发】Android 数据存储 之 SQLite数据库详解
安卓开发之SQLite数据库操作
一、SQLiteDatabase对象 获取SQLiteDatabase对象可以使用SQLiteOpenHelper或者使用静态方法获取(具体内容可以参考开发手册) //使用SQLiteOpenHelper可以获取 DatabaseHelper dbHelper = new DatabaseHelper(Sqlite.this, “sqlite_joyous_db”); SQLiteDatabase  db = dbHelper.getReadableDatabase(); //或者使用静态方法获取 SQLi
苦咖啡
2018/05/08
2.1K0
android之存储篇_SQLite存储方式「建议收藏」
大家好,又见面了,我是全栈君。SQLite是一种转为嵌入式设备设计的轻型数据库,其只有五种数据类型,分别是:
全栈程序员站长
2022/07/20
1.2K0
android之存储篇_SQLite存储方式「建议收藏」
SQLite的增删改查
SQLite的增删改查 1.新建一个SqliteTest 2.新建MyDatavaseHelper类: package com.example.sqlitetest; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.widget.Toast; public clas
Dream城堡
2018/12/18
1.2K0
Android SQLite基本用法(极简)
第一句代码中,创建Activity时会自动生成。在Activity中创建数据库,这里我们给数据库起名为“info.db”,数据库版本号为1,代码如下:
奶油话梅糖
2025/03/03
930
Android SQLite基本用法(极简)
android开发之使用SQLite数据库存储
SQLite 一个非常流行的嵌入式数据库,它支持 SQL 语言,并且只利用很少的内存就有很好的性能。此外它还是开源的,任何人都可以使用它。许多开源项目((Mozilla, PHP, Python)都使用了 SQLite.
全栈程序员站长
2022/03/11
2.6K0
Android:SQLiteOpenHelper类(SQLlite数据库操作)详细解析
当我们完成了对数据库的操作后,记得调用SQLiteDatabase的close()方法释放数据库连接,否则容易出现SQLiteException。
Carson.Ho
2019/02/22
30.8K3
Carson带你学Android:SQLlite数据库操作全解析(SQLiteOpenHelper类)
###4.1 具体代码如下: 建议先下载Demo再进行阅读:Carson的Github:DataBase_Demo
Carson.Ho
2022/03/24
9860
Carson带你学Android:SQLlite数据库操作全解析(SQLiteOpenHelper类)
【Android开发基础系列】Sqlite基础专题
       在Android开发中SQLite起着很重要的作用,网上SQLite的教程有很多很多,不过那些教程大多数都讲得不是很全面。本人总结了一些SQLite的常用的方法,借着论坛的大赛,跟大家分享分享的。
江中散人_Jun
2023/10/16
2440
【Android开发基础系列】Sqlite基础专题
利用SQLChiper对Android SQLite数据库加密
利用SQLChiper对Android SQLite数据库加密 前言: 上篇文章讲了Android studio+SQLCipher加密SQLite数据库的几个坑,跳过这几个坑,那么SQLCipher的前提就处理完成,本片文章接着讲如何使用SQLCiper加密数据库。
红目香薰
2022/11/29
9410
Android数据库安全解决方案,使用SQLCipher进行加解密
本文讲解了如何在Android项目中使用SQLCipher进行数据库加密,通过实例演示了如何在Android项目中创建一个加密的SQLite数据库,并介绍了如何使用SQLCipher进行数据查询和操作。同时,文章还介绍了SQLCipher的API,并给出了在Android项目中使用SQLCipher进行数据库加密的代码示例。
用户1158055
2018/01/05
2.2K0
Android数据库安全解决方案,使用SQLCipher进行加解密
Android数据库加密
SQLite是一个轻量的、跨平台的、开源的数据库引擎,它的读写效率、资源消耗总量、延迟时间和整体简单性上具有的优越性,使其成为移动平台数据库的最佳解决方案(如Android、iOS)。Android系统内置了SQLite数据库,并且提供了一整套的API用于对数据库进行增删改查操作,具体就不详细说明了。
全栈程序员站长
2022/08/27
2.3K0
Android数据库加密
Android SQLite 数据库学习
  SQLite 是一个轻量级数据库,它是D. Richard Hipp建立的公有领域项目,在2000年发布了第一个版本。它的设计目标是嵌入式的,而且占用资源非常低,在内存中只需要占用几百kB的存储空间,这也是Android移动设备采用SQLite数据库的重要原因之一。
星哥玩云
2022/08/17
1.2K0
【Android开发基础系列】数据持久化专题
http://blog.csdn.net/wulianghuan/article/details/8501063
江中散人_Jun
2023/10/16
4760
【Android开发基础系列】数据持久化专题
2014-10-27Android学习------SQLite数据库操作(二)-----数据库的创建--SQLiteHelper extends SQLiteOpenHelper
上篇有篇文章讲了数据库的操作 条件是:数据库已经建好的了,我们只需要从里面获取数据(查询)就可以了,
wust小吴
2022/03/07
7380
2014-10-27Android学习------SQLite数据库操作(二)-----数据库的创建--SQLiteHelper extends SQLiteOpenHelper
推荐阅读
相关推荐
安卓应用安全指南 4.5.1 使用 SQLite 示例代码
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验