【原文地址 点击打开链接】
【原文地址 点击打开链接】
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11952409
我们都知道,Android系统内置了SQLite数据库,并且提供了一整套的API用于对数据库进行增删改查操作。数据库存储是我们经常会使用到的一种存储方式,相信大多数朋友对它的使用方法都已经比较熟悉了吧。在Android中,我们既可以使用原生的SQL语句来对数据进行操作,也可以使用Android API提供的CRUD方法来对数据库进行操作,两种方式各有特点,选择使用哪一种就全凭个人喜好了。
不过,使用SQLite来存储数据却存在着一个问题。因为大多数的Android手机都是Root过的,而Root过的手机都可以进入到/data/data//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,代码如下所示:
- 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) { -
-
} -
- }
接着,打开或新建activity_main.xml作为程序的主布局文件,代码如下所示:
- <</span>LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" -
android:layout_width="match_parent" -
android:layout_height="match_parent" -
android:orientation="vertical" > -
-
<</span>Button -
android:id="@+id/add_data" -
android:layout_width="match_parent" -
android:layout_height="wrap_content" -
android:text="添加数据" -
/> -
-
<</span>Button -
android:id="@+id/query_data" -
android:layout_width="match_parent" -
android:layout_height="wrap_content" -
android:text="查询数据" -
/> -
- </</span>LinearLayout>
- 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(); -
} -
}); -
} -
- }
在添加数据按钮的点击事件里面,我们通过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这个数据库文件:
- adb
shell - cd
/data/data/com.example.sqlciphertest/databases - sqlite3
-line demo.db - .table
尝试查看demo.db中的所有表,结果返回如下图所示:
从图中可以看出,当执行.table命令的时候被拒绝了,原因是数据库文件已加密。
除了使用命令行的方式,我们还可以尝试使用Root Explorer来打开数据库文件,结果如下图所示:
意料之中,果然打开失败了。这就足以说明,目前数据库中的数据是非常安全的,只有在应用程序里通过SQLCipher提供的API才可以访问到数据库里的数据,使用其它的方式都无法获取其数据。
需要提醒的一点是,项目中引入了SQLCipher之后,会让你的程序体积骤然增加,打成APK后大概会变大好几M,是更侧重于文件大小,还是更侧重于程序安全,你应该根据具体的需求做出合适的判断。
好了,今天的讲解到此结束,有疑问的朋友请在下面留言。
- 一直使用sqlite来管理本地的数据,但是Xcode中的SDK中集成的sqlite是免费的,不提供加密模块,但是程序中用到的很多数据,有时候是不想让别人看到,一开始虑修改sqlite的源码,自己重新编译sqlite生成一个带加密模块的静态库,找了一下相关资料,需要修改源码中的makefile和自己实现加密算法等东西,折腾了一下,无果,就果断放弃了。此路不通,那就想别的办法来实现加密功能:现在找到3中方法来实现数据库加密的功能
-
- 方法一、对sqlite中的数据进行加密:
- 就是对数据库中插入的内容先进行aes、MD5等加密后在插入到数据库中,在使用时先从数据库中取出数据,然后在解密在使用这种方式好是好,但是有些致命的问题不能绕过,就是你如果要对某个字段进行模糊查询操作,那么该字段就不能加密,否则的话你不能对该字段进行模糊查询操作;这样一
来该字段还是要暴漏出来,别人还是能看到一些东西的 -
- 方法二、对插入的数据进行简单的字符替换
: - 在插入数据之前,先将一些字符用特定的字符替换掉,在使用的时候在替换回来,对与全是字符集的字段这样操作,也不会影响模糊查询操作(查询之前先用特定字符将输入据替换,在用替换后的数据进行模糊查询,这样就不会有什么影响,同时你也可以用方法一对非查询字段进行加密;这种方法也有个致命的缺点,就是如果你查询的字段是中文的话,这个字符替换就是个大问题,不好解决。
-
- 方法三、使用第三方库的开源库,实现对sqlite数据库的加密找来找去,SQLCipher这个开源框架不错,相关使用方法可以参考官方的文档,说的很详细,照着一步一步的做就可以了http://sqlcipher.net/ios-tutorial/
官方的地址, 同时你可以参考一下这个blog http://blog.csdn.net/kuai0705/article/details/8931996,一些地方不是太详细,以官方文档为主 -
- 如果在编译时提示:No
architectures to compile for (ARCHS=armv6,armv7, VALID_ARCHS=armv7 armv7s则将在Bulid Settings选项下面的Architectures和Valid Architectures里面都改成一样(例如:都填写 armv6 armv7),问题解决。 对于警告 :warning: implicit declaration of function 'sqlite3_key' is invalid in C99 只需要将Bulid Settings选项下的C Language Dialect 改为:C89[-std-c89] 就可以,即使用c89标准