前言
所谓“数据持久化”,就是将内存中的数据(如对象)等存储至可永久保存的存储设备(如文件)中。在Android,数据持久化一般有4种:
1、数据库存储
2、文件存储
3、SharedPreferences存储
4、网络存储
其中SharedPreferences是我们最常用的一种方式,它以键值对的格式存储数据。SharedPreferences有4种操作模式:
1、Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容
2、Context.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件
3、MODE_WORLD_READABLE:表示当前文件可以被其他应用读取
4、MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入
由于后两种将数据暴露给了其他应用,本身就存在很高的安全隐患,因此并不建议开发人员使用!!!(在4.2之后,系统也摒弃了后两种)
研究背景
SharedPreferences除了存储功能外,还可以进行数据的共享,既包括应用程序之间的共享,也包括同一个应用内各组件之间的数据共享。也正因为SharedPreferences的作用十分广泛和方便,几乎所有的APP都会使用。那么,数据的安全问题如何得到有效的保障呢?虽然前面提到允许其他应用读写的操作模式已经被摒弃了,但是由于SharedPreferenes的本质还是文件存储(会将数据存储在xml文件),因此仍然可以利用Root获得文件的访问权限,从而读取文件内容。所以,这种数据持久化方案存在着很大的安全隐患,数据的安全无法得到充分的保障!本文就是借助一台ROOT后的设备,通过编写一个SP文件读取程序,验证是否可以成功获取数据。
准备工作
1、准备一台ROOT的设备,我这里用的是一台pixel手机(至于如何ROOT,网上有大量的教程)
2、安装一个使用了Sharepreferences的APP
实现原理
1、SharePreference的存储路径为/data/data/"+pkgName+"/shared_prefs
2、获取ROOT权限后,利用“ls”命令遍历上述存储路径
3、利用“cat”命令展示文件内容
核心代码
1、遍历SharePreference目录,获取所有xml文件
public static List<String> getSpListByPkg( String pkgName) {
List<String> sps = new ArrayList<>();
ProcessBuilder pb = new ProcessBuilder("/system/bin/sh");
pb.directory(new File("/"));//设置shell的当前目录。
try {
Process proc = pb.start();
//获取输入流,可以通过它获取SHELL的输出。
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader err = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
//获取输出流,可以通过它向SHELL发送命令。
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc
.getOutputStream())), true);
out.println("pwd");
out.println("su root");//执行这一句时会弹出对话框(以下程序要求授予最高权限...),要求用户确认。
out.println("cd /data/data/"+pkgName+"/shared_prefs");//这个目录在系统中要求有root权限才可以访问的。
out.println("ls -l");//打印所有的xml文件
out.println("exit");
out.println("exit");
// proc.waitFor();
String line;
while ((line = in.readLine()) != null) {
if(line.endsWith(".xml")){
String[] infos = line.split("\\s+");
if (infos.length == 8) {
sps.add(infos[7]);
}
}
}
in.close();
out.close();
proc.destroy();
} catch (Exception e) {
System.out.println("exception:" + e);
}
return sps;
}
2、利用“cat”命令展示xml内容
public static String getSpDetail(String pkgName,String spName) {
String content = "";
ProcessBuilder pb = new ProcessBuilder("/system/bin/sh");
pb.directory(new File("/"));//设置shell的当前目录。
try {
Process proc = pb.start();
//获取输入流,可以通过它获取SHELL的输出。
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader err = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
//获取输出流,可以通过它向SHELL发送命令。
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc
.getOutputStream())), true);
out.println("pwd");
out.println("su root");
out.println("cd /data/data/"+pkgName+"/shared_prefs");
out.println("cat "+spName);
out.println("exit");
out.println("exit");
String line;
while ((line = in.readLine()) != null) {
if(!line.equals("/")) {
content += line + "\n";
}
}
in.close();
out.close();
proc.destroy();
} catch (Exception e) {
System.out.println("exception:" + e);
}
return content;
}
效果截图
总结
1、SharedPreferences只是提供文件的存储与读取功能,并不保障数据的安全,因此对于敏感数据,需要自己进行加密处理
2、虽然系统不再允许其他应用操作SharedPreferences,但是仍可以通过ROOT权限成功获取到数据