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

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 安卓应用安全指南 4.5.3 使用 SQLite 高级话题 原书:Android Application Secure Design/Secure Coding Guidebook 译者:飞龙 协议:CC BY-NC-SA 4.04.5.3.1 在 SQL 语句的LIKE断言中使用通配符时,应该实现转义过程当所使用的字符串包含LIKE断言的通配符(%,_),作为占位符的输入值时,除非处理正确,否则它将用作通配符,因此必须根据需要事先转义处理。

安卓应用安全指南 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过程:

//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)。

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

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

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

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

以只读打开数据库:

[...]
// 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。

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()中初始化数据库,打开数据库时设置密码。

简单的代码示例:

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。

相关文章
|
9月前
|
安全 Linux Android开发
Android 安全功能
Android 安全功能
101 0
|
9月前
|
存储 安全 Linux
Android安全启动学习(四):device-mapper-verity (dm-verity)和哈希树
Android安全启动学习(四):device-mapper-verity (dm-verity)和哈希树
415 0
|
2月前
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
4月前
|
安全 网络安全 Android开发
深度解析:利用Universal Links与Android App Links实现无缝网页至应用跳转的安全考量
【10月更文挑战第2天】在移动互联网时代,用户经常需要从网页无缝跳转到移动应用中。这种跳转不仅需要提供流畅的用户体验,还要确保安全性。本文将深入探讨如何利用Universal Links(仅限于iOS)和Android App Links技术实现这一目标,并分析其安全性。
546 0
|
7月前
|
存储 安全 数据安全/隐私保护
🔎Android安全攻防实战!守护你的应用数据安全,让用户放心使用!🛡️
【7月更文挑战第28天】在移动应用盛行的时代,确保Android应用安全性至关重要。本文以问答形式探讨了主要安全威胁(如逆向工程、数据窃取)及其对策。建议使用代码混淆、签名验证、数据加密等技术来增强应用保护。此外,还推荐了加密API、HTTPS通信、代码审计等措施来进一步加强安全性。综上所述,全面的安全策略对于构建安全可靠的应用环境必不可少。#Android #应用安全 #代码混淆 #数据加密
142 3
|
7月前
|
存储 安全 Android开发
安卓应用开发的安全之道
【7月更文挑战第4天】在数字时代,移动应用的安全性至关重要。本文将深入探讨在安卓平台上开发安全应用的最佳实践,包括代码混淆、数据存储加密、网络通信安全、权限管理以及定期的安全审计和更新策略。通过这些措施,开发者可以显著提高他们的应用抵御恶意攻击的能力,保护用户数据免受侵害。
|
8月前
|
安全 网络协议 网络安全
程序与技术分享:Android应用安全之数据传输安全
程序与技术分享:Android应用安全之数据传输安全
|
9月前
|
安全 算法 Android开发
安卓逆向工程与安全分析:保护您的应用知识产权
【4月更文挑战第14天】在数字时代,安卓应用开发者面临知识产权保护的挑战,主要源于安卓系统的开放性和逆向工程。逆向工程能揭示应用源代码,增加被盗用和安全风险。为应对挑战,开发者可采取代码混淆、加密、NDK开发、服务器端验证、定期更新和安全审计等策略。关注安全动态,利用第三方服务也是提升应用安全的重要途径。保护知识产权,确保应用安全,是开发者持续关注和努力的方向。
101 1
|
9月前
|
安全 Android开发 数据安全/隐私保护
代码安全之代码混淆及加固(Android)
代码安全之代码混淆及加固(Android)
234 0
|
9月前
|
安全 算法 Android开发
Android安全启动学习(五):Android Verified Boot 2.0
Android安全启动学习(五):Android Verified Boot 2.0
1734 0

热门文章

最新文章