Android SQLite数据库加密的操作方法
作者:殇神马 发布时间:2021-10-14 11:22:05
一、前言
SQLite是一个轻量级的、跨平台的、开源的嵌入式数据库引擎,也是一个关系型的的使用SQL语句的数据库引擎,
读写效率高、资源消耗总量少、延迟时间少,使其成为移动平台数据库的最佳解决方案(如Android、iOS)
但是Android上自带的SQLite数据库是没有实现加密的,我们可以通过Android Studio直接导出应用创建的数据库文件,然后通过如SQLite Expere Personal 这种可视化工具打开数据库文件进行查看数据库的表结构,以及数据,这就导致存储在SQLite中的数据可以被任何人查看,如果是一些账号密码,或者聊天数据等,那么我们的应用就面临着严重的安全漏洞隐患;
二、数据库加密方法
因为Android自带的SQLite数据库本身是没有实现加密的,那我们如何实现对数据库的加密呢?
(1)对SQLite数据库的数据进行加密
我们可以在程序中对保存到数据库中的数据 进行加密后保存,然后查询数据的时候,对查询的数据进行解密后使用,如果还不希望别人看到数据库的表结构,我们可以对数据库名字,表名,表中的字段名字使用MD5等加密手段加密后再进行操作;
这种方法是可以达到数据库加密的目的的,但是相对来说操作就比较繁琐了
(2)使用SQLCipher对SQLite数据库加密
SQLCipher是基于SQLite基础之上实现了数据库加密的开源库,可以采用第三方的开源框架SQLCipher,SQLCipher是基于原生SQlite数据库进行扩展,实现数据库整体加密(数据库文件加密),提供的数据库的操作接口,和原生的SQLite数据库操作接口基本一样的;我们创建或者打开数据库都需要密码,我们打开数据库时的密码,需要和创建数据库时的密码保护一致,否则打开数据库时会报错,提示打开的文件不是一个数据库文件
net.sqlcipher.database.SQLiteException: file is not a database;
我们导出的数据库文件,通过SQLite Expere Personal这类可视化工具也是无法直接打开的;但是可以使用DB Browser for Sqlite这个数据库查看工具进行查看,查看的时候输入创建数据库时使用的加密密码
SQLCipher的特点:
SQLCipher 占用空间小,性能好,因此非常适合保护嵌入式应用程序数据库,非常适合移动开发。
(1)极快的性能,加密开销低至 5-15%
(2)数据库文件中的数据 100% 已加密,是对所有数据文件,包括数据文件和缓存、结构文件等等进行加密。
(3)使用良好的安全实践(CBC 模式、密钥派生),加密算法是256位 AES 在 CBC 模式
(4)使用 OpenSSL 加密库提供的算法
在Android中集成SQLiteCipher:
-添加SQLiteCipher的依赖
implementation 'net.zetetic:android-database-sqlcipher:4.4.3@aar'
implementation "androidx.sqlite:sqlite:2.0.1"
-使用SQLiteCipher提供的相关接口操作
SQLiteDatabase.loadLibs(this)
val databaseFile = getDatabasePath("demo.db")
if (databaseFile.exists()) databaseFile.delete()
databaseFile.mkdirs()
databaseFile.delete()
val database = SQLiteDatabase.openOrCreateDatabase(databaseFile, "test123", null)
database.execSQL(
"CREATE TABLE " + DatabaseHelper.TABLE_MUSIC_TYPE + " (type_id integer primary key autoincrement not null," +
"type_no integer,type_name text)"
)
database.execSQL(
"insert into " + DatabaseHelper.TABLE_MUSIC_TYPE + " (type_no,type_name) " +
"values ('" + 1 + "','" + "送餐音乐" + "')"
)
上面的代码在调用时,会创建数据库demo.db,传入了数据库密码,并且创建了一个表music_type,并且向表中插入了一条数据;
注意代码中的数据库相关的操作,都是使用SQLIteCipher中的相关接口即net.sqlcipher.database包名下的相关接口,不要使用成了原生SQLite的相关接口
SQLiteDatabase.loadLibs(this)
val databaseFile = getDatabasePath("demo.db")
val database = SQLiteDatabase.openOrCreateDatabase(databaseFile, "test123", null)
val cursor = database.rawQuery(
"select * from " + DatabaseHelper.TABLE_MUSIC_TYPE,
null
)
var musicTypeList: MutableList<MusicTypeBean> = mutableListOf();
while (cursor.moveToNext()) {
var musicTypeBean = MusicTypeBean();
musicTypeBean.id = cursor.getInt(cursor.getColumnIndex("type_no"))
musicTypeBean.name = cursor.getString(cursor.getColumnIndex("type_name"))
musicTypeList.add(musicTypeBean)
}
cursor.close()
Log.e(TAG, "onClick: " + musicTypeList.size)
上述代码就是查询demo.db数据库中的music_type表中的数据,获取数据库对象的时候,注意传入的密码和创建数据库时要保持一致;
上面使用SQLiteCipher创建数据库和表,以及向表中插入数据,查询表中的数据,除了创建数据库获取可读写数据库对象和原生SQLite API有些区别一样,其他执行SQL语句,查询表中数据的API 和原生 SQlite API是完全一样的;
SQLiteCipher结合Room框架使用
我们知道在使用SQLite数据库的时候,我们往往会使用一些比较方便的ORM(对象关系映射)框架来帮助我们操作数据库,如GreenDAO,Room(Jetpack组件)等,那如何将SQLiteCipher结合这些ORM框架使用;我们这里介绍一下Google Jetpack组件中的ORM框架 Room结合SQLiteCipher使用;
其实Room结合SQLiteCipher使用,就是在创建数据库时候,需要先创建一个SupportFactory
,SupportFactory中会传入通过SQLiteCipher中的SQLiteDatabase获取的密码字节数据
SQLiteDatabase.loadLibs(this)
val passphrase = SQLiteDatabase.getBytes("test123".toCharArray())
val factory = SupportFactory(passphrase, object : SQLiteDatabaseHook {
override fun preKey(database: SQLiteDatabase?) {
LogUtil.e(TAG, "preKey")
}
override fun postKey(database: SQLiteDatabase?) {
LogUtil.e(TAG, "postKey")
}
}, true)
然后在创建数据库的时候,通过Room自带的openHelperFactory()方法传入创建的SupportFactory即可,这样就能创建加密数据库了;其他操作,就按照Room正常的操作即可
var mInstance= Room
.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
DB_NAME
).addCallback(object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
Log.e(TAG, "onCreate: ")
initMusicTypeData(context, db)
}
}).openHelperFactory(factory)
.build()
查看并导出加密数据库文件
-导出数据库文件
我们手机通过USB连接电脑之后,打开开发者模式,然后在Android Studio菜单栏中的View->
Tool Windows->Device File Explorer
然后在Device File Explorer中进入 data/data/应用包名/databases中找到我们创建的数据库文件demo.db,然后我们可以右键改文件Save As 导出该数据库文件
前面我们已经提到过,可以通过DB Browser for SQLite来查看加密的数据库文件
下载地址:https://sqlitebrowser.org/dl/
下载安装之后,我们打开安装目录下的DB Browser for SQLCipher.exe程序,然后通过菜单栏中的文件->打开数据库->打开导出的加密数据库文件,然后输入数据库文件的加密密码,就是我们在程序中SQLiteCipher加密数据库文件时使用的密码,输入正确密码后,可以正常打开数据库文件
来源:https://blog.csdn.net/mq2856992713/article/details/120540119


猜你喜欢
- 序列化序列化:将对象转换为二进制序列在网络中传输或保存到磁盘反序列化:从网络或磁盘中将二进制序列转换为对象注意:对象必须实现Serializ
- 最近该忙的都忙完了,自己自定义一直是个弱项,也一直想整个钟表玩玩,网上看了一圈,学习了不少,下面自己做做自定义首先,制作钟表第一步,肯定是画
- 本文实例讲述了java实现新浪微博Oauth接口发送图片和文字的方法。分享给大家供大家参考。具体如下:基于网上很多人利用新浪api开发新浪微
- 效果图简单的效果图(使用开源库)[FlowLayout](“ https://github.com/hongyangAndroid/Flow
- 如何实现 WPF 代码查看器控件框架使用.NET40;Visual Studio 2019;代码展示需要使用到AvalonEdit是基于WP
- Java 中的 BIO、NIO和 AIO 理解为是 Java 语言对操作系统的各种 IO 模型的封装。程序员在使用这些 API 的时候,不需
- springboot启动是通过一个main方法启动的,代码如下@SpringBootApplicationpublic class Appl
- 本实例是为了实现在管理后台实现微信菜单的添加删除管理。1、首先我们需要新建一个数据库表用于存放menu菜单项可包含的字段有id、父类id、n
- 一、HandlerThread的介绍及使用举例  
- 对于导航组件的使用方式不是本文的重点,具体使用可以参考官方文档,导航组件框架是通过f
- Web控件DropDownList和WinForm控件ComboBox机制不一样。ComboBox没有对应的ListItem需要自己写一个:
- 本人工作有一个月多了。对于android很多东西,都有了新的了解或者说真正的掌握。为了让更多的像我这样的小白少走弯路,所以我会坚持将我在工作
- Feign简介Feign 是一个声明web服务客户端,这便得编写web服务客户端更容易,使用Feign 创建一个接口并对它进行注解,它具有可
- 随着现在分布式架构越来越盛行,在很多场景下需要使用到分布式锁。很多小伙伴对于分布式锁还不是特别了解,所以特地总结了一篇文章,让大家一文读懂分
- 四舍五入是我们小学的数学问题,这个问题对于我们程序猿来说就类似于1到10的加减乘除那么简单了。在讲解之间我们先看如下一个经典的案
- 1.新建一个数组,把原来数组的内容搬到新数组中。这种方法实现的思路是:先新建一个数组(前提条件是长度得比原来的长),然后把原来数组的内容搬到
- 方式一: 配置文件 application.propertiesserver.port=7788方式二: java启动命令# 以应用参数的方
- //FilterKalman.csnamespace FusionFiltering{public class FilterKalman &
- 本文实例讲述了DevExpress中ChartControl实现柱状图演示的方法。分享给大家供大家参考。具体实现方法如下:关键代码如下:us
- Android自带的SeekBar是水平的,要垂直的,必须自己写一个类,继承SeekBar。一个简单的垂直SeekBar的例子:(但是它其实