Android数据库安全解决方案,使用SQLCipher进行加解密

2023-11-03



转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11952409

我们都知道,Android系统内置了SQLite数据库,并且提供了一整套的API用于对数据库进行增删改查操作。数据库存储是我们经常会使用到的一种存储方式,相信大多数朋友对它的使用方法都已经比较熟悉了吧。在Android中,我们既可以使用原生的SQL语句来对数据进行操作,也可以使用Android API提供的CRUD方法来对数据库进行操作,两种方式各有特点,选择使用哪一种就全凭个人喜好了。

不过,使用SQLite来存储数据却存在着一个问题。因为大多数的Android手机都是Root过的,而Root过的手机都可以进入到/data/data/<package_name>/databases目录下面,在这里就可以查看到数据库中存储的所有数据。如果是一般的数据还好,但是当涉及到一些账号密码,或者聊天内容的时候,我们的程序就会面临严重的安全漏洞隐患。那么今天,就让我们一起研究一下如何借助SQLCipher来解决这个安全性问题。

SQLCipher是一个在SQLite基础之上进行扩展的开源数据库,它主要是在SQLite的基础之上增加了数据加密功能,如果我们在项目中使用它来存储数据的话,就可以大大提高程序的安全性。SQLCipher支持很多种不同的平台,这里我们要学习的自然是Android中SQLCipher的用法了。

下面我们就开始吧,首先要把Android项目所依赖的SQLCipher工具包下载下来,下载地址是:

https://s3.amazonaws.com/sqlcipher/SQLCipher+for+Android+v2.2.2.zip

接着解压这个工具包,会看到里面有assets和libs这两个目录,稍后需要将这两个目录中的内容添加到Android项目当中。那么现在我们就来新建一个Android项目,项目名就叫SQLCipherTest。

观察SQLCipherTest的项目结构,发现里面也分别有一个assets目录和一个libs目录,那么现在就可以把SQLCipher工具包中这两个目录里的内容复制过来。并不需要复制全部文件,选择必要的文件进行复制就可以了,完成以后项目结构图如下所示,图中显示的文件都是必要的。

                            

到这里准备工作就全部完成了,接下来我们开始编写代码。首先创建一个MyDatabaseHelper继承自SQLiteOpenHelper,注意这里使用的并不是Android API中的SQLiteOpenHelper,而是net.sqlcipher.database包下的SQLiteOpenHelper,代码如下所示:

  1. import android.content.Context;  
  2. import net.sqlcipher.database.SQLiteDatabase;  
  3. import net.sqlcipher.database.SQLiteDatabase.CursorFactory;  
  4. import net.sqlcipher.database.SQLiteOpenHelper;  
  5.   
  6. public class MyDatabaseHelper extends SQLiteOpenHelper {  
  7.       
  8.     public static final String CREATE_TABLE = "create table Book(name text, pages integer)";  
  9.   
  10.     public MyDatabaseHelper(Context context, String name, CursorFactory factory, int version) {  
  11.         super(context, name, factory, version);  
  12.     }  
  13.   
  14.     @Override  
  15.     public void onCreate(SQLiteDatabase db) {  
  16.         db.execSQL(CREATE_TABLE);  
  17.     }  
  18.   
  19.     @Override  
  20.     public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {  
  21.   
  22.     }  
  23.   
  24. }  
import android.content.Context;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteDatabase.CursorFactory;
import net.sqlcipher.database.SQLiteOpenHelper;

public class MyDatabaseHelper extends SQLiteOpenHelper {
	
	public static final String CREATE_TABLE = "create table Book(name text, pages integer)";

	public MyDatabaseHelper(Context context, String name, CursorFactory factory, int version) {
		super(context, name, factory, version);
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL(CREATE_TABLE);
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {

	}

}
除了引入的包不一样了,其它的用法和传统的SQLiteOpenHelper都是完全相同的。可以看到,我们在onCreate()方法中创建了一张Book表,Book表里有name和pages这两个列。

接着,打开或新建activity_main.xml作为程序的主布局文件,代码如下所示:

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="match_parent"  
  3.     android:layout_height="match_parent"  
  4.     android:orientation="vertical" >  
  5.       
  6.     <Button   
  7.         android:id="@+id/add_data"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="wrap_content"  
  10.         android:text="添加数据"  
  11.         />  
  12.       
  13.     <Button   
  14.         android:id="@+id/query_data"  
  15.         android:layout_width="match_parent"  
  16.         android:layout_height="wrap_content"  
  17.         android:text="查询数据"  
  18.         />  
  19.   
  20. </LinearLayout>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <Button 
        android:id="@+id/add_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="添加数据"
        />
    
    <Button 
        android:id="@+id/query_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="查询数据"
        />

</LinearLayout>
这里只是简单地放置了两个按钮,分别用于添加和查询数据。接下来打开或新建MainActivity作为程序主Activity,代码如下所示:
  1. public class MainActivity extends Activity {  
  2.       
  3.     private SQLiteDatabase db;  
  4.   
  5.     @Override  
  6.     protected void onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8.         setContentView(R.layout.activity_main);  
  9.         SQLiteDatabase.loadLibs(this);  
  10.         MyDatabaseHelper dbHelper = new MyDatabaseHelper(this"demo.db"null1);  
  11.         db = dbHelper.getWritableDatabase("secret_key");  
  12.         Button addData = (Button) findViewById(R.id.add_data);  
  13.         Button queryData = (Button) findViewById(R.id.query_data);  
  14.         addData.setOnClickListener(new OnClickListener() {  
  15.             @Override  
  16.             public void onClick(View v) {  
  17.                 ContentValues values = new ContentValues();  
  18.                 values.put("name""达芬奇密码");  
  19.                 values.put("pages"566);  
  20.                 db.insert("Book"null, values);  
  21.             }  
  22.         });  
  23.         queryData.setOnClickListener(new OnClickListener() {  
  24.             @Override  
  25.             public void onClick(View v) {  
  26.                 Cursor cursor = db.query("Book"nullnullnullnullnullnull);  
  27.                 if (cursor != null) {  
  28.                     while (cursor.moveToNext()) {  
  29.                         String name = cursor.getString(cursor.getColumnIndex("name"));  
  30.                         int pages = cursor.getInt(cursor.getColumnIndex("pages"));  
  31.                         Log.d("TAG""book name is " + name);  
  32.                         Log.d("TAG""book pages is " + pages);  
  33.                     }  
  34.                 }  
  35.                 cursor.close();  
  36.             }  
  37.         });  
  38.     }  
  39.   
  40. }  
public class MainActivity extends Activity {
	
	private SQLiteDatabase db;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		SQLiteDatabase.loadLibs(this);
		MyDatabaseHelper dbHelper = new MyDatabaseHelper(this, "demo.db", null, 1);
		db = dbHelper.getWritableDatabase("secret_key");
		Button addData = (Button) findViewById(R.id.add_data);
		Button queryData = (Button) findViewById(R.id.query_data);
		addData.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				ContentValues values = new ContentValues();
				values.put("name", "达芬奇密码");
				values.put("pages", 566);
				db.insert("Book", null, values);
			}
		});
		queryData.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Cursor cursor = db.query("Book", null, null, null, null, null, null);
				if (cursor != null) {
					while (cursor.moveToNext()) {
						String name = cursor.getString(cursor.getColumnIndex("name"));
						int pages = cursor.getInt(cursor.getColumnIndex("pages"));
						Log.d("TAG", "book name is " + name);
						Log.d("TAG", "book pages is " + pages);
					}
				}
				cursor.close();
			}
		});
	}

}
可以看到,在onCreate()方法中首先调用了SQLiteDatabase的loadLibs()静态方法将SQLCipher所依赖的so库加载进来,注意这里使用的是net.sqlcipher.database包下的SQLiteDatabase。然后我们创建了MyDatabaseHelper的实例,并调用getWritableDatabase()方法去获取SQLiteDatabase对象。这里在调用getWritableDatabase()方法的时候传入了一个字符串参数,它就是SQLCipher所依赖的key,在对数据库进行加解密的时候SQLCipher都将使用这里指定的key。

在添加数据按钮的点击事件里面,我们通过ContentValues构建了一条数据,然后调用SQLiteDatabase的insert()方法将这条数据插入到Book表中。

在查询数据按钮的点击事件里面,我们调用SQLiteDatabase的query()方法来查询Book表中的数据,查询到的结果会存放在Cursor对象中,注意这里使用的是net.sqlcipher包下的Cursor。然后对Cursor对象进行遍历,并将查询到的结果打印出来。

现在运行一下程序,先点击添加数据按钮,再点击查询数据按钮,刚刚添加的那条数据就应该在控制台里打印出来了。

有没有感觉到使用SQLCipher提供的API和使用Android原生的数据库API,操作起来几乎是一模一样的。没错,SQLCipher对Android SDK中所有与数据库相关的API都制作了一份镜像,使得开发者可以像操作普遍的数据库文件一样来操作SQLCipher,而所有的数据加解密操作,SQLCipher都在背后帮我们处理好了。

话说写到这里,我们都一直还没体验一下SQLCipher加密后的效果呢,现在就来看一看吧,首先通过命令行的方式来访问demo.db这个数据库文件:

  1. adb shell  
  2. cd /data/data/com.example.sqlciphertest/databases  
  3. sqlite3 -line demo.db  
  4. .table  
adb shell
cd /data/data/com.example.sqlciphertest/databases
sqlite3 -line demo.db
.table

尝试查看demo.db中的所有表,结果返回如下图所示:

  

从图中可以看出,当执行.table命令的时候被拒绝了,原因是数据库文件已加密。

除了使用命令行的方式,我们还可以尝试使用Root Explorer来打开数据库文件,结果如下图所示:

                                        

意料之中,果然打开失败了。这就足以说明,目前数据库中的数据是非常安全的,只有在应用程序里通过SQLCipher提供的API才可以访问到数据库里的数据,使用其它的方式都无法获取其数据。

需要提醒的一点是,项目中引入了SQLCipher之后,会让你的程序体积骤然增加,打成APK后大概会变大好几M,是更侧重于文件大小,还是更侧重于程序安全,你应该根据具体的需求做出合适的判断。

好了,今天的讲解到此结束,有疑问的朋友请在下面留言。

如果喜欢我写的文章,请小手一抖,为我投上一票,真心非常感谢你的支持。

投票地址:http://vote.blog.csdn.net/blogstaritem/blogstar2013/sinyu890807

源码下载,请点击这里

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android数据库安全解决方案,使用SQLCipher进行加解密 的相关文章

  • android.app包---------ActivityManager类介绍

    ActivityManager类介绍 ActivityManager与系统与所有正在运行Activity进行交互 相关方法介绍 getDeviceConfigurationInfo 获取设备配置属性值 getMemoryClass 返回当前
  • 使用fastboot工具刷入recovery.img、boot.img、system.img等

    下载解压 fastboot工具 解压FastBoot工具 zip 将解压得到的 FastBoot文件夹复制到任意盘如 D盘 将要刷入手机的recovery img recovery img等放到FastBoot文件夹 安装好手机型号对应的U
  • Android 3D滑动菜单完全解析,实现推拉门式的立体特效

    转载请注明出处 http blog csdn net guolin blog article details 10471245 在上一篇文章中 我们学习了Camera的基本用法 并借助它们编写了一个例子 实现了类似于API Demos里的图
  • UncaughtExceptionHandler示例使用

    概述 UncaughtExceptionHandler是用来catch线程内的没有被捕获到的exception 可以在uncaughtException方法中对这些异常进行统一处理 用法 UncaughtExceptionHandler是一
  • Android RecycleView列表使用GridLayoutManager 均分子项Item,且左右宽度相同

    1 需求描述 列表分为一列两个 两个子项宽度一致 且左右边距一样 就是要好看 子项宽度适配手机 高度适配宽度 2 问题描述 但是我们直接设置的时候 他的子项会在给他的布局的左边 于是我想到了设置下子项的左右边距 但是android手机屏幕太
  • android.accounts包

    包 android accounts 英文原文 http developer android com reference android accounts package summary html 版本 Android 4 0 r1 译者署
  • Android数据库安全解决方案,使用SQLCipher进行加解密

    转载请注明出处 http blog csdn net guolin blog article details 11952409 我们都知道 Android系统内置了SQLite数据库 并且提供了一整套的API用于对数据库进行增删改查操作 数
  • Java中的四种引用

    Java中存在四种引用 它们分别是 1 强引用 StrongReference 强引用是使用最普遍的引用 如果一个对象具有强引用 那垃圾回收器绝不会回收它 当内存空间不足 Java虚拟机宁愿抛出OutOfMemoryError错误 使程序异
  • Android res文件夹下资源定义及使用

    1 颜色 RGB ARGB RRGGBB AARRGGBB 颜色资源应该位于
  • Java中String类的isEmpty方法、null以及""的区别

    一直以来对String的这三个空挺晕的 刚好同事问我 我也学习下 从别人博客上看到的是这样的 isEmpty 分配了内存空间 值为空 是绝对的空 是一种有值 值 空 分配了内存空间 值为空字符串 是相对的空 是一种有值 值 空字串 null
  • android 日期控件

    相关布局文件
  • Android下拉刷新完全解析,教你如何一分钟实现下拉刷新功能

    转载请注明出处 http blog csdn net guolin blog article details 9255575 最近项目中需要用到ListView下拉刷新的功能 一开始想图省事 在网上直接找一个现成的 可是尝试了网上多个版本的
  • android.content包-----ClipboardManager

    ClipboardManager类介绍 Clipboardmanager类通过getSystemService String 方法进行实例化操作 ClipboardManger类的相关方法很简单 包含set和get剪切板的数据 剪切板的数据
  • WebView 加载不出网页,一片空白

    今天在项目上加载网页时 发现一只加载不出来 emmm 就看了下以往的项目 发现遗漏的地方不止一点哦 在此做个总结 1 权限配置 确保在 AndroidManifest xml 文件中添加了网络权限
  • android获取string.xml的值

    为什么需要把应用中出现的文字单独存放在string xml文件中呢 一 是为了国际化 当需要国际化时 只需要再提供一个string xml文件 把里面的汉子信息都修改为对应的语言 如 English 再运行程序时 android操作系统会根
  • Android Studio如何添加工程(project)为library(针对非gradle)

    这篇文章还是针对非gradle build的工程 gradle build有一些差别 在Eclipse要引用别的工程为本工程的library很简单 但是在Android Studio还是稍稍有点小复杂的 那如何引用别的工程为本工程的libr
  • Android SurfaceView

    下面就贴上一个小程序代码 主要运用SurfaceView来实现在屏幕上画一个圆 你可以通过按方向键和触摸屏幕来改变圆的位置 代码 Activity java view plain copy print package com view im
  • android.accessibilityservice包介绍

    android accessibilityservice 英文原文 http developer android com reference android accessibilityservice package summary html
  • 转载的开源干货

    android相关 第三方库 awesome android ui 大量 Android UI UX 库 大城小黄 recyclerview animators 一个关于RecyclerView items的动画库 一个简单的Recycle
  • ANDROID版本号和版本名称的重要性介绍

    转载请注明出处http blog csdn net y150481863 article details 41249159 来自 http blog csdn net y150481863 当我们在刚开始学习ANDROID的时候 可能不会过

随机推荐

  • 什么是CDN?CDN的原理和作用是什么?

    一 什么是CDN CDN全称Content Delivery Network 即内容分发网络 CDN是Content Delivery Network 内容分发网络 的缩写 是一种利用分布式节点技术 在全球部署服务器 即时地将网站 应用 视
  • 关系数据库

    关系 关系 描述实现事物的一张二维表 外码 关系A中的一组非主属性 其与关系B的主属性对应 则称关系A这组属性为A的外码 关系A为参照关系 关系B为被参照关系 关系完整性 实体完整性 主属性不能取空值 主属性应具有唯一区分性 参照完整性 外
  • 区块链入门系列之共识算法

    区块链入门系列文章 区块链基本概念和名词解释 P2P 共识算法 梅克尔 帕特里夏树 从零开始搭建区块链 这里写自定义目录标题 区块链入门系列文章 前言 POW POS PBFT Raft 其他共识算法 前言 前文已经说过 区块链从本质上来说
  • task1

    Task1 伯努利模型 P X 1 p P X 0 1 p 三要素 1 极大似然估计 模型 伯努利模型 策略 经验风险最小化 极大似然估计 等价于当模型是条件概率分布 损失函数是对数损失函数时的经验风险最小化 算法 极大化似然 P X p
  • MySQL的存储过程

    存储过程是组为了完成特定功能的SQL语句集合 存储过程在使用过程中是将常用或者复杂的工作预先使用SQL语句写好并用一个指定的名称存储起来 这个过程经编译和优化后存储在数据库服务器中 当需要使用该存储过程时 只需要调用它即可 存储过程在执行上
  • linux多节点zookeeper(不限于zookeeper)批量调起(举例,问题排查)

    小脚本 废话不多说直接来 bin bash flag 1 DfsOrAll 2 启动zookeeper 这里 hadoop01 hadoop02 hadoop03 都是节点别名 取代ip地址 可在 etc hosts配置 for i in
  • 翻转的卡片

    前言 第二篇 CodingStartup起码课 的视频练习 这几天都在看他的视频 然后跟着做出效果来 HTML CSS 制作翻牌效果 效果图 要点 使用 position 设置 2 个卡片重叠 正为 正面 反为 背面 transform r
  • pandas统计分析(下)——数据格式化、分组统计

    数据格式化 在数据处理以后需要对数据进行格式化 以增加数据的可读性 设置小数位数 主要使用round函数实现四舍五入 decimals参数用于设置保留小数的位数 round decimals 0 args kwargs decimals 每
  • android对webkit做了哪些封装,lAndroidwebkit简介及开发遇到的一些问题.doc

    lAndroidwebkit简介及开发遇到的一些问题 Android webkit简介 张立鹏 M厂开发五部目录 1 webkit架构2 2 Application3 2 1 WebViewClient里面几个重要方法3 2 2 WebCh
  • sql net message from client

    sql net message from client 2011 05 09 15 18 17 分类 等待事件 标签 字号大中小 订阅 sql net message from client大部分情况下对于数据库来说是空闲等待事件 表示数据
  • [Gradle中文教程系列]-跟我学Gradle-5.3:依赖-管理依赖的版本(传递(transitive)\排除(exclude)\强制(force)\动态版本(+))

    http blog csdn net pkaq article details 53906668
  • 抓包查看http + json 中的 json信息

    一 抓包查看 抓包中过滤http报文 因为json信息在http response中 点击 http 1 1 200 OK 报文 查看这个报文中的 http gt hypertext transfer protocol gt line ba
  • AndroidStudio编译调试aosp11R 的Launcher3

    1 下载aosp并编译 2 下载Launcher3 可以直接使用aosp中的 也可以使用git单独下载 git clone https android review googlesource com platform packages ap
  • 模式分类识别

    模式分类识别 BP神经网络多特征分类预测 Matlab完整程序 目录 模式分类识别 BP神经网络多特征分类预测 Matlab完整程序 分类结果 基本介绍 程序设计 参考资料 分类结果 基本介绍
  • Linux中的用户登录和管理指令

    关机 重启指令 shutdown h now 立刻进行关机 shutdown h 1 1分钟之后自动关机 同时该指令和shutdown 作用一致 shutdown r now 现在重新启动计算机 r代表reboot halt 立即关机 re
  • js怎么实现数组里的数据相加_JS怎么对数组内元素进行求和

    JS数组内元素求和 我们可以使用reduce 方法查找或计算数字数组的总和 该reduce 方法对数组的每个成员执行指定的reducer函数 从而生成单个输出值 下面我们就结合具体的代码示例 给大家介绍JS数组内元素求和的实现方法 代码示例
  • 文章生成器-原创文章生成器

    在网络营销领域 优质文章是吸引新客户和保留老客户的重要工具 然而 生成高质量且符合SEO优化的文章并不是一件容易的事情 这就是为什么网站文章生成器如今备受欢迎的原因 而在众多的文章生成工具中 147GPT批量生成文章软件是一款非常出色的文章
  • ACM金牌学长,算法竞赛经验分享

    大家好 我是编程熊 不少读者问我 本科打算法竞赛 你如何训练的呀 有什么经验么 于是小熊写一篇ACM算法竞赛入门和进阶指南 分享一下经验和学习方法 也许你可能不参加算法竞赛 但知道厉害的人如何学习 训练 一步步变强 也是可以借鉴和学习的 如
  • qt中comobox下拉框的样式

    参考博客 https blog csdn net li235456789 article details 50915842 1 实现效果如下 1 实现代码如下 放在样式表中实现 QComboBox drop down subcontrol
  • Android数据库安全解决方案,使用SQLCipher进行加解密

    转载请注明出处 http blog csdn net guolin blog article details 11952409 我们都知道 Android系统内置了SQLite数据库 并且提供了一整套的API用于对数据库进行增删改查操作 数