在Android Intent中保护额外数据

7
我正在使用Intent在新任务中启动新的Activity。该Intent包含一些私有数据,这些数据在其额外功能中由该Activity需要。其他应用程序不应该能够读取这些数据。
我们已经调查了是否确实未泄露这些数据。我们发现通过使用从getRecentTasks()获取的RecentTaskInfo,任何具有GET_TASK权限的任意应用程序都可以读取此额外数据。
这并不是很安全。
我们一旦发现这个漏洞,就停止了查询。还有没有其他方式泄露这些数据?如何确保额外数据不被其他应用程序读取?
3个回答

8

从Android 4.1.1开始,为了防止第三方应用程序使用RecentTaskInfo读取额外信息,添加了一项额外的权限。该权限(android.Manifest.permission.GET_DETAILED_TASKS)只能由系统获取。如果没有该权限,则在通过RecentTaskInfo返回baseIntent之前,额外信息将被交换出去。

来自提交的注释http://androidxref.com/4.2.2_r1/history/frameworks/base/services/java/com/android/server/am/ActivityManagerService.java#8238e717df4bc5eebf15f97172d68af3599a95bb

添加新的签名级别权限以获取任务详情。 第三方应用现在无法访问与任务相关联的意图的附加信息,以防止其中的私人数据泄漏。 Change-Id:I95af9e181ac42557bc8b981807e7ddd266a88d0e 因此,似乎正在努力使意图额外的传输更安全以传输敏感信息。我不知道这些额外信息是否存在其他泄漏方式,但至少从JB开始,这些额外信息看起来是安全的。

很好,这确实很酷。我需要进一步调查一下。谢谢! - CommonsWare

6
这个Intent携带了Activity所需的一些私有数据,存储在extras中。为什么要将标识符传递给extras中的私有数据?因为只有Activity才能将这些标识符转换成私有数据(例如数据库查询)。
我们发现,通过使用getRecentTasks()中的RecentTaskInfo,任何具有GET_TASK权限的应用程序都可以读取这些额外数据。
是的,我在近两年前就写过博客,其他人可能更早之前就已经写过了。
所有启动其他组件的请求都通过操作系统进程进行,因此数据始终“泄漏”到操作系统中。
根据您对Intent的处理方式,您可能会以其他方式泄漏它(例如,将Intent本身作为Parcelable传递给其他应用程序)。
如何确保extra中的数据不可被其他应用程序读取?
您无法做到这一点。再次强调,不要将私有数据放在activity extras中,而是使用标识符来获取该私有数据。

尽管我同意你的解决方案可以使用(顺便说一下,它将适用于“所有”API级别),但似乎更近期的Android版本实际上修复了你博客中描述的问题。请查看我在回答中提供的提交。 - baske
我可以接受操作系统能够读取我的数据,问题在于非操作系统应用程序。如果我正确理解您的解决方案,它意味着设置ContentProvider。这只是将安全问题移动到不同的位置:如何确保查询仅在预期活动访问时返回答案?当多个应用程序需要接收安全信息但不允许查看彼此的信息时,我不认为权限是可行的解决方案。 - user2186703
如果我正确理解您的解决方案,它意味着设置ContentProvider - 不是这样。数据具有标识符的概念,例如数据库表中的主键,已经存在了几十年。由于Android没有存在几十年,因此有一些方法可以使用标识符查找数据,而不使用Android特定的构造,如“ContentProvider”。因此,通过“标识符”,我指的是您的数据库表的键,或者您的“HashMap”的键,或者您的CSV表的行号,或者您的“JSON”对象的键等。 - CommonsWare
如果你要使用ContentProvider来实现这个功能,你可以使用intent“数据”与FLAG_GRANT_READ_URI_PERMISSION一起,为接收活动提供特定于URI的一次性读权限,然后该活动可以使用查询检索私有数据。但是,如果您的目标是JB+,您可能希望考虑坚持最初的解决方案,因为它似乎比Jellybean之前更安全。 (请参见其他答案) - baske

1
你拥有私有存储空间,只有你的应用程序能够读取。在非root设备上,你存储在那里的信息仅对你的应用程序可访问。
你可以使用SharedPreference来存储你的数据 - 数据存储在你的应用程序指定的私有存储中。
或者,你可以直接使用私有存储,并像这样将任意文件传输到其中:
FileOutputStream fos;
try {
    fos = openFileOutput (FILENAME, Context.MODE_PRIVATE);
    fos.write (string.getBytes ());
    fos.close ();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接