首页 > 代码库 > 【Android平台中的安全编程】の #00-不要在外部存储(SD卡)中存放未加密的敏感信息
【Android平台中的安全编程】の #00-不要在外部存储(SD卡)中存放未加密的敏感信息
本文翻译自https://www.securecoding.cert.org/confluence/display/java/DRD00-J.+Do+not+store+sensitive+information+on+external+storage+%28SD+card%29+unless+encrypted+first,有增删改。
Android提供了几种保存持久化应用数据的选择,其中之一就是外部存储(/sdcard, /mnt/sdcard)。外部存储包括设备内部的微型或标准大小的SD卡,挂载到PC上的Android设备存储卡以及Android/obb目录。
Android4.1之前的版本,存放在外部存储的文件是world-readable(能够被任何用户读取的)和world-writable(能够被任何用户写入)。从Android4.1到Android4.3,一个app想要写入外部存储的任意文件时,只需在AndroidManifest文件中声明WRITE_EXTERNAL_STORAGE权限。但从Android4.4开始,引入了基于目录结构创建分组和文件模式,这使得一个app在外部存储中的只能在以自己包名命名的目录下才具有文件的读写权限。非系统级的app只允许在Android/data/<package-name>/目录下操作。因此,每个app的文件读写权限被独立开来,不能互相访问。
上面描述的访问权限限制的不足,导致写入到外部存储的文件可能存在被同一设备上不同的app修改和读取的风险(Android4.4之前版本)。
Android API指南[Android Guild 2013]关于Storage Options给出了如下的警告信息:如果用户将外部存储挂载到PC上或者直接移除了,会导致外部存储不可用,而且没有安全措施保证存放在外部存储上的文件。所有的应用都可以读写存放在外部存储的文件,而且用户可以随意删除它。
开发者不应该在外部存储中存放未加密的敏感信息,因为外部存储的文件不能保证可用性,完整性和保密性。
[不符合安全要求的代码示例]
下面的代码在外部存储中创建一个文件,并保存了敏感的信息。
private String filename = "myfile" private String string = "sensitive data such as credit card number" FileOutputStream fos = null; try { file file = new File(getExternalFilesDir(TARGET_TYPE), filename); fos = new FileOutputStream(file, false); fos.write(string.getBytes()); } catch (FileNotFoundException e) { // handle FileNotFoundException } catch (IOException e) { // handle IOException } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { } } }
[概念验证]
一个应用一般存放在外部存储的文件目录结构如下所示:
/sdcard/Android/data/com.company.app/files/save/appdata/save_appdata
[符合安全要求的解决方案#1 将文件保存到内部存储中]
下面的代码使用openFileOutput()方法在应用的data目录中创建“myfile”文件,并将访问权限设置为MODE_PRIVATE,这样保证其他app访问不了该文件。
private String filename = "myfile" private String string = "sensitive data such as credit card number" FileOutputStream fos = null; try { fos = openFileOutput(filename, Context.MODE_PRIVATE); fos.write(string.getBytes()); fos.close(); } catch (FileNotFoundException e) { // handle FileNotFoundException } catch (IOException e) { // handle IOException } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { } } }
[符合安全要求的解决方案#2]
在将文件保存到外部存储之前,先对文件内容进行加密。