0x00 数据安全

Android操作系统自问世以来凭借其开放性和易用性成为当前智能手机的主流操作系统之一,作为与人们关系最密切的智能设备,越来越多的通讯录、短信、视频等隐私数据以明文的方式保存在手机中,这些数据虽然有锁屏密码或者指纹保护,但是由于Android系统自身的安全性,专业人士可以毫不费力的获取到手机数据镜像,个人隐私面临泄露风险。另一方面,日益繁荣的移动互联网应用也是基于用户数据和应用程序构成,如何保护这些用户数据安全性是应用发展的基石。随着人们对数据安全重视,如何更好地保护用户数据成为移动应用开发者的一大挑战。
       本文以Android开发实践出发,由浅入深讨论Android数据的存储、加密等实现方法供移动开发进行参考。并结合自身经验探讨对Android数据安全的一些思考。

0x01 常用数据存储方法及实例

文件

存储数据最直接的方法就是以文件的形式保存在手机中,Android开发主要基于Java语言,因此,在文件读写等基本操作相同,文件操作和数据流来源于java.IO.*,但是对于Android而言,开发者需要注意一下几点:
       1、 文件目录 Android权限管理中各个应用程序有独立的存储空间,存储结构如下:

       2、常见文件目录及路径
/data/data/(packageName)/cache 目录 应用缓存文件,目录获取方法:File cache = getCacheDir()
/data/data/(packageName)/files 目录,即应用一般文件,目录获取方法:File file = getFilesDir()
/data/data/(packageName)/shared_prefs 目录,存放应用SharedPreference文件目录位置
/data/data/(packageName)/databases 目录,应用数据库(SQLite)
/storage/emulated/0/sdcard 内置sd卡目录,获取方法:String sdcard = getInnerSDCardPath()
/storage/extSdCard 外置sd卡目录,获取方法:String exsdcard = Environment.getExternalStorageDirectory().getPath()
       在Android手机中,获取默认sd卡目录方法明确,但是由于Android手机本身不一定支持外置sd卡,或者有/没有插入外置sd卡,因此在获取外sd卡时需要留心有坑,一是避免异常,二是分清内置和外置。
       关键词:位置。通过文件保存用户或者应用数据时,首先要遵循Android开发的规则,在应用目录中根据文件的类型选择保存的外置。在sd卡中存放时,避免直接保存在根目录下,这样做是避免造成用户手机文件管理的混乱;二是避免文件被修改、删除等。

数据库

Android 数据库采用SQLite,SQLite 是一款内置到移动设备上的轻量型的数据库,是遵守ACID(原子性、一致性、隔离性、持久性)的关联式数据库管理系统。Android开发中可以通过SQLiteOpenHelper或者自定义类SQLiteOpenHelper来实现数据存储查询修改的功能。此外SQLite数据库支持加密操作,通过sqlite3.exe或者SQLiteConnection均可对数据库进行加密操作。SQLiteEncrypt、SQLiteCrypt、SQLCipher等工具提供对数据库的加密操作,但是前两个需要收费,SQLCipher是开源工具,GitHub地址为: SQLCipher;通过SQLiteConnection类加密方法如下:

SQLiteConnection conn = new SQLiteConnection("Data Source=TestDatabase.sqlite;Version=3;");
conn.SetPassword("password");
conn.open()

SharedPreferences存储

SharedPreferences存储方式是Android中存储轻量级数据的一种方式,内部以Map方式进行存储,保存的数据以xml格式存放在本地的/data/data/(packagename)/shared_prefs文件夹下。轻量级数据要求保存在shared_prefs中<key,value>数据value大小不能太大,数据太大会给系统GC、内存带来压力,甚至造成程序卡顿。

SharedPreferences pref = getSharedPreferences("test", MODE_PRIVATE);
SharedPreferences.Editor editor=pref.edit();
SharedPreferences.Editor editor=pref.edit();
editor.putString("name", "root");//保存字符串
editor.putInt("age", 12);//保存整型数据 editor.commit(); //putXXX 方法中第一个参数是key,第二参数为value
SharedPreferences pref = getSharedPreferences(“setting”, 0);
pref.getInt("key_name", -1); // getting Integer
pref.getFloat("key_name", null); // getting Float
pref.getLong("key_name", null); // getting Long
//getXXX方法第一个参数表示key名称,第二个表示value默认值

0x02 Android加密算法及实现

DES,对称加密,同理有3DES,3DES在DES的基础上进行3重加密,以牺牲效率来提高加密安全性。

//加密
public static byte[] encrypt(byte[] data,String key){try {byte[] bkey = key.getBytes();// 初始化向量IvParameterSpec iv = new IvParameterSpec(bkey);DESKeySpec desKey = new DESKeySpec(bkey);// 创建密匙工厂,把DESKeySpec转换成securekeySecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");SecretKey securekey = keyFactory.generateSecret(desKey);Cipher cipher = Cipher.getInstance("DES");// 用密匙初始化Cipher对象cipher.init(Cipher.ENCRYPT_MODE, securekey, iv);// 现在,获取数据并加密// 加密操作return cipher.doFinal(data);} catch (Throwable e) {e.printStackTrace();}return null;
}//解密
public static byte[] decrypt(byte[] src, String key) throws Exception {byte[] bkey = key.getBytes();// 初始化向量IvParameterSpec iv = new IvParameterSpec(bkey);// 创建一个DESKeySpec对象DESKeySpec desKey = new DESKeySpec(bkey);// 创建密匙工厂SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// 把DESKeySpec对象转换成SecretKey对象SecretKey securekey = keyFactory.generateSecret(desKey);// Cipher对象实际完成解密操作Cipher cipher = Cipher.getInstance("DES");// 用密匙初始化Cipher对象cipher.init(Cipher.DECRYPT_MODE, securekey, iv);// 真正开始解密操作return cipher.doFinal(src);
}

AES 高级加密标准,用来替代DES的对称加密算法

//AES 加密
public static byte[] encrypt(byte[] data, byte[] key) {try {KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者kgen.init(128, new SecureRandom(key));// 128位的key生产者SecretKey secretKey = kgen.generateKey();// 根据key生成密钥byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥SecretKeySpec aesKey = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES密钥Cipher cipher = Cipher.getInstance("AES");// 创建密码器cipher.init(Cipher.ENCRYPT_MODE, aesKey);// 初始化为加密模式的密码器// 加密return cipher.doFinal(data);}catch (NoSuchAlgorithmException e){e.printStackTrace();} catch (NoSuchPaddingException e) {e.printStackTrace();}catch (InvalidKeyException e) {e.printStackTrace();} catch (IllegalBlockSizeException e) {e.printStackTrace();} catch (BadPaddingException e) {e.printStackTrace();}return null;
}//AES 解密
public static byte[] decrypt(byte[] data, byte[] key) {try {KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者kgen.init(128, new SecureRandom(key));SecretKey secretKey = kgen.generateKey();// 根据用户密码,生成一个密钥byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥SecretKeySpec aesKey = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥Cipher cipher = Cipher.getInstance("AES");// 创建密码器cipher.init(Cipher.DECRYPT_MODE, aesKey);// 初始化为解密模式的密码器//解密return cipher.doFinal(data);  } catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (NoSuchPaddingException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (IllegalBlockSizeException e) {e.printStackTrace();} catch (BadPaddingException e) {e.printStackTrace();}return null;
}

对称加密特点是实现效率快,但是由于加/解密密钥相同,在密钥保存、分发、安全各方面出现许多问题,例如密钥管理,密钥泄露。基于此,将加密密钥和解密密钥分开,形成客户端端使用公钥加密,服务端用私钥解密的非对称加密,将加解密密钥分开,加密密钥不必担心泄露风险。常用的非对称加密算法如RSA。
       RSA加解密实现

// 生成 public and private keys
public static KeyPair buildKeyPair() throws NoSuchAlgorithmException {final int keySize = 2048;KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");keyPairGenerator.initialize(keySize);return keyPairGenerator.genKeyPair();
}
public static byte[] encrypt(PrivateKey privateKey, byte[] data) throws Exception {Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.ENCRYPT_MODE, privateKey);//加密return cipher.doFinal(data);
}public static byte[] decrypt(PublicKey publicKey, byte [] enData) throws Exception {Cipher cipher = Cipher.getInstance("RSA");cipher.init(Cipher.DECRYPT_MODE, publicKey);//解密return cipher.doFinal(enData);
}

在常用数据加密方法中,通常也会遇到md5、sha-256算法等,但是这些算法是明文的hash值,哈希算法和加密算法的本质是是否可逆,即由密文通过运算得到明文。特别注意,base64编码是一种编码格式,除了增加可读性难度及转义没有任何安全性。

0x03 存储安全进阶

在上文中介绍了常用的Android数据存储方式和加密算法,通过直观的介绍进入到Android存储安全中,在实际的应用中数据存储安全性问题是一个复制的系统性问题,不仅仅表现在开发中,从数据结构到编码以及密钥的生成和管理都会涉及到数据存储安全。
       文件的隐藏 Android创建隐藏文件或者文件夹,在文件名或者文件夹名字前加一个“.”号即可(这里是英文输入法下的.号),隐藏文件/文件夹可直接进行读写。这是一个容易被开发者忽略的问题,乍一看好像没什么难度,问题在于开发者和用户视角问题。由于Android手机默认带文件查看器,因此用户可以轻松查看、修改sdcard目录下的文件,当使用隐藏文件是最大的作用是避免用户误操作。
       密钥的保存 如果将密钥保存到手机文件中,或者通过硬编码的方式写在代码中,容易被逆向出来,在通常情况下,采用对称加密密钥需要保存在用户手机中,这和安全性想违背。通常最好的方式是不要保有密钥,通过固定数据或者字符串做加密密钥因子,例如用户唯一账号属性等。
       编码方式 Android代码主要有Java编码,打包文件时Java代码打包成dex文件防到安装包文件中,但是dex文件容易被逆向回smali代码或者Java文件。虽然目前混淆和加壳甚至是虚拟机保护(VMP)技术已经很成熟,简单逆向工作无法获取代码逻辑和硬编码字符串,但是Java代码依然存在很高的安全风险。因此,将加解密相关操作通过Native代码实现很有必要,不仅保证效率而且在so保护技术之上安全性更高。

0x04 Android数据安全思考

随着移动互联网深入发展,目前移动应用正在发生质的改变。相比繁荣初始的粗狂、野蛮,现在的移动应用开始考虑安全和质量,特别是当前我国互联网信息安全的大形势,数据安全关乎企业和应用的生存的前提,保护应用数据安全至关重要。在Android数据存储安全中,由于Android系统的安全机制,用户获取root权限后可以访问手机所有目录,包括应用私有目录,因此,数据存储要考虑到一个白盒环境,或者非可信环境。这种情况下,数据加密的密钥成为关键。一机一密、动态密钥、密钥白盒等手段各有优缺点。一机一密需要保护密钥生成方法逻辑;动态密钥需要考虑密钥时效性,有效性以及链路安全;密钥白盒由于目前没有广泛认可,在兼容性安全性方面有待考验。
       (后面有时间针对一机一密、动态密钥、密钥白盒单独介绍)

本文作者root001,文章来源freebuf,原文链接 http://www.freebuf.com/articles/terminal/185320.html

Android数据存储安全实践相关推荐

  1. Android 数据存储 利用SQLiteDatabase实现简单的学生管理

    转载请注明出处:明桑Android 这是作为上一篇Android 数据存储 如何搞定SQLite Database的实例练习,之所以单独列出来是因为除了数据库方面的知识,还涉及其它方面的知识,所以就写 ...

  2. Android数据存储——2.文件存储_B_资源文件

    今天学习Android数据存储--文件存储_资源文件 把资源文件mybook.txt放入项目目录下的res资源文件夹下的raw文件夹下(没有则新建),PS:mybook.txt存为UTF-8编码. X ...

  3. Android数据存储——2.文件存储_C_DOM解析XML文档

    今天学习Android数据存储--文件存储_DOM解析XML文档 位于org.w3c.dom操作XML会比较简单,就是将XML看做是一颗树,DOM就是对这颗树的一个数据结构的描述,但对大型XML文件效 ...

  4. Android数据存储之GreenDao 3.0 详解

    前言: 今天一大早收到GreenDao 3.0 正式发布的消息,自从2014年接触GreenDao至今,项目中一直使用GreenDao框架处理数据库操作,本人使用数据库路线 Sqlite----> ...

  5. < Android数据存储> 任务二 应用程序数据文件夹里的文件读写

    :zh]Android中提供了两个方法用来打开应用程序的数据文件夹IO流. 1.FileInputStream openFileInput(String name):参数name表示某个文件名,该方法 ...

  6. 5 Android数据存储 任务二 应用程序数据文件夹里的文件读写 ,

    Android中提供了两个方法用来打开应用程序的数据文件夹IO流. 1.FileInputStream openFileInput(String name):参数name表示某个文件名,该方法用于打开 ...

  7. Android数据存储:Shared Preferences

    Android数据存储之SharedPreferences 在Android系统中提供了多种存储技术.通过这些存储技术可以将数据存储在各种存储介质上, Android 为数据存储提供了如下几种方式: ...

  8. android+默认存储,Android 数据存储之SP存储,内部存储,外部存储

    Android 数据存储之SP存储,内部存储,外部存储 Android提供了多种数据存储的技术来永久的保存应用数据,以便于开发者能够根据自己的需求来选择合适的数据存储方案,主要有SharedPrefe ...

  9. 【Android数据存储】ContentProvider详细介绍(附实例源码)

    1.ContentProvider是什么? ContentProvider--内容提供者.它是一个类,这个类主要是对Android系统中进行共享的数据进行包装,并提供了一组统一的访问接口供其他程序调用 ...

最新文章

  1. 轻量级NLP工具Trankit开源,中文处理更精准,超越斯坦福Stanza,内存占用小45%
  2. 从ThinkPHP框架核心讨论C、E、G、L、T、I、N...等函数
  3. ZOJ 38727(贪心)
  4. htmlparser解析网站时服务器返回的文件编码和页面编码不一致问题
  5. android文件存储token,ANDROID 学习笔记(二) 用户登陆问题 TOKEN SESSION 缓存
  6. Go语言学习之encoding/json包
  7. 成功解决Error:invalid character in identifier
  8. Python 网络爬虫笔记4 -- 信息标记与提取
  9. jenkins中通过Publish Over SSH将项目部署到远程机器上
  10. 《C++ Primer 第五版》(第4.11-4.12节)——static_cast,const_cast和reinterpret_cast类型转换, 运算符优先级表
  11. Scala零基础教学【61-80】
  12. 01-09 Linux三剑客-awk
  13. CentOS6.5 firefox安装flash插件
  14. ADS仿真 之 直流仿真示例
  15. 百旺如何看是否清卡_百旺税控盘会自动清卡吗
  16. 示波器探头对测量可能引起的10种影响
  17. LNMT架构部署:Linux+Nginx+Mysql+Tomcat
  18. 解决:No routes matched location “/“
  19. 中国集成灶10大品牌排行榜揭晓,公认的集成灶10大品牌是哪几个?
  20. 看代码,学strings包

热门文章

  1. 对比学习(Contrastive Learning)中的损失函数
  2. gb2312的字符串(包括中午)转16进制字符串以及反转义原始字符
  3. 电子专业英语(持续更新)
  4. 微信电商小程序开发有什么好处呢
  5. 关闭Windows Defender实时保护,暂时关闭和永久关闭方法
  6. 银河麒麟中的录屏软件
  7. 开工大吉 | Cocos Store 精品资源推荐
  8. android ios 实时视频,Twitter推出适用于Android和iOS设备的实时视频
  9. Matlab函数gscatter使用
  10. FileZilla远程上传文件失败原因和解决办法