作者 | Alan Bavosa
译者 | 平川
策划 | 丁晓昀
一段时间以来,人们都“知道”,作为移动平台的 Android 不如 iOS 安全,这已经成为常识。似乎除了消费者,每个人都知道。2021 年 8 月对 10000 名移动消费者进行的一项全球调查发现,iOS 和 Android 用户的安全期望基本一致。
然而,尽管消费者有这样的期望,而且从本质上讲,一个移动平台并不一定比另一个平台更安全,但移动应用很少能实现 Android 和 iOS 的安全功能对等。事实上,许多移动应用甚至缺少最基本的安全保护措施。让我们看看这是为什么。
1 移动应用安全需要多层次防御
大多数安全专家和第三方标准组织都会同意,移动应用安全需要多层次防御,包括以下核心领域的多种安全特性:
- 代码混淆和应用护盾(Application Shielding):保护移动应用的二进制文件和源代码,防止逆向工程。
- 数据加密:保护应用中存储和使用的数据。
- 安全通信:保护在应用和应用后端之间传递的数据,包括确保用于建立可信连接的数字证书的真实性和有效性。
- 操作系统防护:保护应用免受未经授权的操作系统修改(如 rooting 和越狱)所影响。
开发人员应该在应用的 iOS 和 Android 版本中均衡地实现这些功能的组合,形成一致的安全防御。而且,他们应该在开发周期的早期添加这些功能——这个概念被称为安全“左移”。听起来很容易吧?理论上,是的,但在实践中,如果使用“传统”方法,要实现移动应用多层次安全防御实际上是相当困难的。
多年来,移动开发人员一直试图使用传统的工具集来实现应用内移动应用安全,包括第三方开源库、商业移动应用安全 SDK 或专用编译器。第一个主要的挑战是,移动应用的安全从来无法通过“银弹”实现。由于移动应用在不受保护的环境中运行,并存储和处理大量有价值的信息,有许多方法可以攻击它们。黑客有无穷无尽的、免费提供而又非常强大的工具集可以使用,而且可以全天候地研究和攻击应用而不被发现。
2 移动安全要求
因此,为了构建一个强大的防御体系,移动开发人员需要实施一个既“广”且“深”的多层次防御。所谓“广”,我指的是不同保护类别的多种安全特性,它们彼此相互补充,如加密和混淆。所谓“深”,我指的是每个安全特性都应该有多种检测或保护方法。例如,一个越狱检测 SDK 如果只在应用启动时进行检查,就不会很有效,因为攻击者很容易绕过。
或者考虑下反调试,这是一种重要的运行时防御,可以防止攻击者使用调试器来执行动态分析——他们会在一个受控的环境中运行应用,为的是了解或修改应用的行为。有许多类型的调试器——有一些基于 LLDB——是针对原生代码的,如 C 或 Objective C,其他的在 Java 或 Kotlin 层进行检查,诸如此类。每个调试器连接和分析应用的工作方式都略有不同。因此,为了使反调试防御奏效,应用需要识别正在使用的多种调试方法,并动态地进行恰当的防御,因为黑客会继续尝试不同的调试工具或方法,直到他们找到一个可以成功的。
3 防篡改
安全要求清单并不仅限于此。每个应用都需要防篡改功能,如校验和验证、预防二进制补丁,以及应用的重新打包、重新签名、模拟器和仿真器,等等。毫不夸张,仅是针对一个操作系统研究和实现这些功能或保护方法中的一项,就需要至少几个人周的开发时间。而且还要有一个前提,就是移动开发人员已经拥有特定安全领域的专业知识,但情况往往并非如此。复杂度可能会快速增加,到目前为止,我们只讨论了一个保护类别——运行时或动态保护。想象一下,如果提到的每个功能都需要一到两周的开发时间,那么实现全部安全特性得付出多大的时间成本。
4 防越狱 /Rooting
接下来,你还需要操作系统层面的保护,如防越狱 /rooting,在移动操作系统遭破坏的情况下保护应用。越狱 /rooting 使移动应用容易受到攻击,因为它允许对操作系统和文件系统进行完全的管理控制,破坏了整个安全模型。而且,仅仅检测越狱 /rooting 已经不够了,因为黑客们一直在不断地改进他们的工具。要说最先进的越狱和 rooting 工具,在 iOS 上是 Checkra1n,在 Android 上是 Magisk——还有许多其他的工具。其中,还有一些工具用于隐藏或掩盖活动及管理超级用户权限——通常授予恶意应用。朋友们,如果你使用 SDK 或第三方库实现了越狱或 rooting 检测,那么你的保护措施很有可能已经过时或者很容易被绕过,尤其是在没有对应用的源代码进行充分混淆的情况下。
5 代码混淆
如果你使用 SDK 或第三方库来实现安全防护,那在未混淆的应用中几乎没什么用——为什么?因为黑客使用 Hopper、IDA-pro 等开源工具,就可以很容易地反编译或反汇编,找到 SDK 的源代码,或使用类似 Frida 这样的动态二进制工具箱,注入他们自己的恶意代码,修改应用的行为,或简单地禁用安全 SDK。
代码混淆可以防止攻击者了解移动应用的源代码。而且,我们总是建议使用多种混淆方法,包括混淆本地代码或非本地代码和库,以及混淆应用的逻辑结构或控制流。例如,可以使用控制流混淆或重命名函数、类、方法、变量等来实现。不要忘了还要混淆调试信息。
从现实世界的数据中可以看出,大多数移动应用都缺乏足够的混淆,只混淆了应用的一小部分代码,这项对超过 100 万个 Android 应用的研究清楚地说明了这一点。正如该研究指出的那样,造成这种情况的原因是,对于大多数移动开发人员来说,依赖专用编译器的传统混淆方法实在是太复杂和费时,难以全面实施。相反,许多开发人员只实现了单一的混淆功能,或者只混淆了代码库的一小部分。在这项研究中,研究人员发现,大多数应用只实现了类名混淆,这本身很容易被攻陷。拿书打个比方,类名混淆本身就像是混淆了一本书的“目录”,但书中所有实际的页和内容却并没有混淆。这种表面的混淆相当容易被绕过。
6 数据保护和加密
接着说数据保护,你还需要借助加密来保护应用和用户数据——在移动应用中,有很多地方存储着数据,包括沙盒、内存以及应用的代码或字符串。要自己实现加密,有很多棘手的问题需要解决,包括密钥衍生(key derivation)、密码套件和加密算法组合、密钥大小及强度。许多应用使用了多种编程语言,每一种都需要不同的 SDK,或者会导致你无法控制的不兼容性,又或是需要你无法访问的依赖。而数据类型的差异也有复杂性增加和性能下降的风险。
然后,还有一个典型的问题,即在哪里存储加密密钥。如果密钥存储在应用内部,那它们可能会被反向工程的攻击者发现,然后他们就可以用来解密数据。这就是为什么我们说动态密钥生成是一个非常重要的功能。通过动态密钥生成,加密密钥只在运行时生成,而不会存储在应用或移动设备上。此外,密钥只使用一次,可以防止攻击者发现或截获它们。
那么传输中的数据呢?仅靠 TLS 是不够的,因为有很多方法可以侵入应用的连接。检查和验证 TLS 会话和证书很重要,这可以确保所有的证书和 CA 都是有效且真实的,受到行业标准加密的保护。这可以防止黑客获得 TLS 会话的控制权。然后还有证书固定,可以防止连接到遭到入侵的服务器,或保护服务器,拒绝遭到入侵的应用连接(例如,如果你的应用被变成了一个恶意机器人)。
7 欺诈、恶意软件、防盗版
最后,还有反欺诈、反恶意软件和反盗版保护,你可以在上述基线保护的基础上增加防护层,用于防止非常高级或专门的威胁。这些保护措施可能包括可以防止应用覆盖攻击、自动点击器、钩子框架和动态二进制工具、内存注入、键盘记录器、密钥注入或可访问性滥用的功能,所有这些都是移动欺诈或移动恶意软件的常用武器。
不难想象,即使是实现上述功能的一个子集,也需要大量的时间和资源。到目前为止,我只是谈了一个强大的安全防御所需的特性和功能。即使你内部有资源和所需的技能组合,那么拼凑出一个防御体系的行动挑战又是什么呢?让我们探讨一下开发团队可能会遇到的一些实施挑战。
8 不同平台和框架之间的实现差异
鉴于用于构建移动应用的 SDK/ 库及原生或非原生编程语言之间存在无数的框架差异和不兼容,开发人员将面临的下一个问题是如何分别为 Android 和 iOS 实现这些安全功能。虽然软件开发工具包(SDK)提供了一些标准安全功能,但没有 SDK 能普遍覆盖所有的平台或框架。
当开发人员试图使用 SDK 或开源库来实现移动应用安全时,所面临的一个主要挑战在于,这些方法都依赖于源代码,需要对应用代码进行修改。而结果是,这些方法中的每一个都明确地与应用所使用的特定编程语言绑定,并且还暴露给了各种编程语言或是这些语言和框架的包“依赖”。
通常,iOS 应用使用 Objective-C 或 Swift 构建,而 Android 应用使用 Java 或 Kotlin 以及使用 C 和 C 编写原生库。例如,假如你想对存储在 Android 和 iOS 应用中的数据进行加密。如果你找到了一些第三方 Android 加密库亦或是 Java 或 Kotlin 的 SDK,它们不一定适用于应用中使用的 C 或 C 代码部分(原生库)。
在 iOS 中也是如此。你浏览 StackOverflow 时可能会发现,在 Swift 中常用的 Cryptokit 框架对 Objective C 不起作用。
那么,非原生或跨平台应用呢?它们是完全不同的赛道,因为你要处理的是 JavaScript 等 Web 技术和 React Native、Cordova、Flutter 或 Xamarin 等非原生框架,它们无法直接(或根本不能)使用为原生语言构建的 SDK 或库。此外,对于非原生应用,你可能无法获得相关的源代码文件,从源头实现加密。
关于这个问题,有一个真实的例子,请看 Stack Overflow 上的这篇帖子。开发人员需要在一个 iOS 应用中实现代码混淆,其中 React Native(一个非原生框架)和 Objective C(一种原生编码语言)之间存在多个依赖关系。由于 iOS 项目中没有可以混淆 React Native 代码的内置库,开发人员需要使用一个外部包(依赖关系 #1)。此外,该外部包还依赖下游的一个库或包来混淆 JavaScript 代码(依赖关系 #2)。现在,如果第三方库的开发人员决定废弃该解决方案,会发生什么?我们的一个客户就面临着这样的问题,这导致他们的应用不符合 PCI 标准。
那么,你认为需要多少开发人员来实现我刚才描述的哪怕是一小部分功能?又需要多长时间?你有足够的时间在现有的移动应用发布过程中实现所需的安全功能吗?
9 DevOps 是敏捷 自动化,传统安全是单体 手动
移动应用是在一个快节奏、灵活且高度自动化的敏捷模式下开发和发布的。为了使构建和发布更快速、更简单,大多数 Android 和 iOS DevOps 团队都围绕 CI/CD 和其他自动化工具构建了最佳管道。另一方面,安全团队无法访问或查看 DevOps 系统,而且大多数安全工具并不是针对敏捷方法构建的,因为它们在很大程度上依赖于手动编程或实施,在这种情况下,单个安全功能的实施时间可能会长于发布时间表允许的时间。
为了弥补这些不足,一些组织在向公共应用商店发布应用之前,会使用代码扫描和渗透测试,以深入探查漏洞和其他移动应用问题。当发现漏洞时,企业就会面临一个艰难的决定:是在未进行必要保护的情况下发布应用,还是推迟发布,让开发人员有时间来解决安全问题。当这种情况发生时,推荐的安全保护措施往往会被忽视。
开发人员并不懒惰,而是他们用于实现安全保护的系统和工具根本无法匹配现代敏捷 /DevOps 开发的快节奏。
10 实现强大的移动应用安全和平台对等的五个步骤
一般来说,自动化是实现安全对等和强大的移动应用安全的关键所在。以下是在应用发布周期内将移动应用安全打造为应用组成部分的五个步骤。
第 1 步:明确希望得到什么样的安全成果
开发、运营和安全团队必须就移动安全预期达成一致。对于组织作为起点的安全目标,人们要有一个共同的理解,如 OWASP Mobile Top 10、TRM 移动应用安全指南和移动应用安全验证标准(MASVS)。一旦确定了目标并选择了标准,所有团队成员都要知道这对他们的工作流有何影响。
第 2 步:移动应用安全的实施必须自动化
安全非常复杂,手动编码很慢,而且容易出错。评估并利用自动化系统,借助人工智能和机器学习(ML)将安全集成到移动应用中。通常情况下,这些都是无代码平台,可以自动将安全构建到移动应用中,它们通常被称为安全构建系统。
第 3 步:将安全作为开发周期的一部分——安全左移
移动应用安全模型左移是指,移动开发人员需要在构建应用的同时构建安全特性。
一旦选择了自动化安全实施平台,就应该将其整合到团队的持续集成(CI)和持续交付(CD)流程中,这可以加速开发生命周期,所有团队——开发、运营和安全——在整个冲刺期间都应该保持密切合作。此外,企业可以为每个 Android 和 iOS 应用所需的特定安全特性创建可重复使用的移动安全模板,从而更接近实现平台对等。
第 4 步:确保即时确认和验证
如果没有办法即时验证所需的安全功能是否包含在发布中,那么在发布会议上就会出现争执,可能导致应用发布或更新延期。验证和确认应该自动记录,防止最后一刻的发布混乱。
第 4 步:确保即时确认和验证
开发团队需要可预测性和明确的预算。通过采用自动化的安全方法,应用开发团队可以减少人员和开发费用的意外变化,因为它消除了手动将安全编码到移动应用时固有的不确定性。
11 小结
安全对等问题是一个大问题,但它是一个更大问题的一部分,即移动应用普遍缺乏安全性。通过在安全实现中采用与特性开发相同或更高程度的自动化,开发人员可以确保他们针对每个平台发布的每一个应用都免受黑客、骗子和网络犯罪分子的侵害。
作者简介:
Alan Bavosa 是 Appdome 的安全产品副总裁。长期以来,他一直担任安全产品执行官,曾是 Palerra(被 Oracle 收购)和 Arcsight(被 HP 收购)的产品主管。
原文链接:
https://www.infoq.com/articles/secure-mobile-apps-parity-problem/
点击底部阅读原文访问 InfoQ 官网,获取更多精彩内容!
今日好文推荐
没有内卷、996 和“老板”,乐视过上神仙日子?WPS 重申“删除用户本地文件”一事;小米被指违反 GPL 协议 | Q 资讯
相比高人气的 Rust、Go,为何 Java、C 在工具层面进展缓慢?
史上最强韦伯太空望远镜:任何不可靠的软件故障点都可能让百亿美元泡汤
微软开始封禁商业开源:从 App Store 入手,7 月 16 日生效?!