我正在为Android开发一款支付处理应用程序,我想防止黑客访问APK文件中的任何资源、资产或源代码。

如果有人将.apk扩展名更改为.zip,那么他们可以将其解压缩并轻松访问应用程序的所有资源和资产,并且可以使用dex2jar和Java反编译器访问源代码。对Android APK文件进行反向工程非常容易-有关更多详细信息,请参阅堆栈溢出问题从APK文件到项目的反向工程。

我已经使用了Android SDK提供的Proguard工具。当我对使用签名密钥库和Proguard生成的APK文件进行反向工程时,我得到了混淆的代码。

然而,Android组件的名称保持不变,一些代码(如应用程序中使用的关键值)保持不变。根据Proguard文档,该工具无法混淆Manifest文件中提到的组件。

现在我的问题是:

如何完全防止Android APK的反向工程?这可能吗?我如何保护应用程序的所有资源、资产和源代码,使黑客无法以任何方式破解APK文件?有没有办法让黑客攻击变得更加困难甚至不可能?我还能做什么来保护APK文件中的源代码?


当前回答

以下是一些可以尝试的方法:

使用混淆和ProGuard等工具。加密部分源代码和数据。在应用程序中使用专有的内置校验和来检测篡改。引入代码以避免在调试器中加载,也就是说,让应用程序能够检测调试器并退出/终止调试器。将身份验证分离为在线服务。使用应用程序多样性在验证设备之前,使用指纹技术,例如,来自不同子系统的设备的硬件签名。

其他回答

如果我们想让逆向工程(几乎)不可能实现,我们可以将应用程序放在一个高度防篡改的芯片上,该芯片在内部执行所有敏感的内容,并与一些协议通信,使控制GUI在主机上成为可能。即使是防篡改芯片也不能100%防裂;他们只是设定了比软件方法高得多的标准。当然,这是不方便的:该应用程序需要一些小的USB疣来保持芯片插入设备。

这个问题并没有揭示出想要如此谨慎地保护这个应用程序的动机。

如果目的是通过隐藏应用程序可能存在的任何安全缺陷(已知或其他)来提高支付方法的安全性,那么这是完全错误的。如果可行的话,安全敏感位实际上应该是开源的。您应该尽可能方便任何审查您的应用程序的安全研究人员查找这些信息并仔细检查其操作,并与您联系。付款应用程序不应包含任何嵌入证书。也就是说,不应该有任何服务器应用程序仅仅因为设备具有来自工厂的固定证书而信任该设备。支付交易应仅凭用户的凭证进行,使用正确设计的端到端认证协议,避免信任应用程序、平台或网络等。

如果目标是防止克隆,除了防篡改芯片之外,你无法采取任何措施来保护程序不被反向工程和复制,从而使某人将兼容的支付方法融入自己的应用程序,从而导致“未经授权的客户”。有一些方法可以使开发未经授权的客户端变得困难。一种方法是基于程序完整状态的快照创建校验和:所有状态变量,所有内容。GUI、逻辑等等。克隆程序将不具有完全相同的内部状态。当然,它是一个状态机,具有类似的外部可见状态转换(可以通过输入和输出观察到),但几乎没有相同的内部状态。服务器应用程序可以询问程序:您的详细状态是什么?(即给我一个所有内部状态变量的校验和)。这可以与虚拟客户端代码进行比较,虚拟客户端代码在服务器上并行执行,并经过真正的状态转换。第三方克隆人必须复制真实程序的所有相关状态变化,才能给出正确的响应,这将阻碍其开发。

我可以看出这个问题有很好的答案。除此之外,您可以使用FacebookReDex来优化代码。ReDex在.dex级别工作,而ProGuard在.class级别工作。

应用程序安全的第一条规则:攻击者获得不受限制的物理或电子访问权限的任何机器现在都属于您的攻击者,无论其实际位置或您为此支付的费用。应用程序安全的第二条规则:任何离开攻击者无法穿透的物理边界的软件现在都属于您的攻击者,无论您花费了多少时间对其进行编码。第三条规则:任何离开攻击者无法穿透的物理边界的信息都属于您的攻击者,无论它对您有多大价值。

信息技术安全的基础是基于这三个基本原则;唯一真正安全的计算机是被锁在法拉代笼子里的保险箱里,被锁在钢笼子里。有些计算机的大部分使用寿命都处于这种状态;每年一次(或更少),他们为可信的根认证机构生成私钥(在一大群目击者面前,摄像机记录下他们所在房间的每一寸)。

现在,大多数计算机不在这些类型的环境下使用;他们在户外,通过无线电台连接到互联网。简而言之,他们很脆弱,他们的软件也是如此。因此,他们不值得信任。为了有用,计算机及其软件必须知道或做某些事情,但必须小心确保它们永远不会知道或做足够的事情来造成损坏(至少不会造成超出单个机器范围的永久性损坏)。

你已经知道这一切了;这就是为什么要保护应用程序的代码。但是,其中存在第一个问题;混淆工具可以使代码变得一团糟,让人类试图挖掘,但程序仍然必须运行;这意味着应用程序的实际逻辑流及其使用的数据不受混淆的影响。只要有一点韧性,攻击者就可以简单地对代码进行反混淆,在某些情况下,这甚至是不必要的,在这种情况下,他所看到的不是其他东西,而是他正在寻找的东西。

相反,你应该努力确保攻击者不能对你的代码做任何事情,无论他多么容易获得代码的清晰副本。这意味着,没有硬编码的秘密,因为一旦代码离开你开发它的建筑,这些秘密就不是秘密。

这些硬编码的键值应该从应用程序的源代码中完全删除。相反,他们应该在三个地方之一;设备上的易失性内存,攻击者很难(但仍然不是不可能)获得的脱机副本;永久位于服务器集群上,您可以使用铁腕控制访问;或者存储在与您的设备或服务器无关的第二个数据存储中,例如物理卡或用户的存储器中(这意味着它最终将存储在易失性存储器中,但不需要很长时间)。

考虑以下方案。用户将应用程序的凭据从内存输入设备。不幸的是,您必须相信用户的设备尚未被键盘记录器或木马程序破坏;在这方面,你能做的最好的就是实现多因素安全,记住关于用户使用过的设备的难以伪造的识别信息(MAC/IP、IMEI等),并提供至少一个额外的通道,通过该通道可以验证在陌生设备上的登录尝试。

凭证一旦输入,就会被客户端软件混淆(使用安全散列),并丢弃纯文本凭证;他们达到了目的。混淆后的凭据通过安全通道发送到证书认证服务器,该服务器再次对它们进行散列,以生成用于验证登录有效性的数据。这样,客户端就永远不知道与数据库值实际比较的内容,应用程序服务器永远不知道它接收到的验证内容背后的明文凭证,数据服务器永远不了解它存储的验证数据是如何生成的,中间的人即使安全通道被破坏,也只会看到胡言乱语。

一旦验证,服务器将通过信道发回令牌。令牌仅在安全会话中有用,由随机噪声或会话标识符的加密(因此可验证)副本组成,客户端应用程序必须在同一信道上向服务器发送此令牌,作为任何请求的一部分。客户机应用程序会多次这样做,因为它不能做任何涉及金钱、敏感数据或其他可能会对其造成损害的事情;它必须改为要求服务器执行此任务。客户端应用程序永远不会将任何敏感信息写入设备本身的永久内存,至少不会以明文形式写入;客户端可以通过安全通道向服务器请求对称密钥来加密服务器将记住的任何本地数据;在稍后的会话中,客户端可以向服务器请求相同的密钥来解密数据以在易失性存储器中使用。这些数据也不会是唯一的副本;客户机存储的任何内容也应以某种形式传输到服务器。

显然,这使您的应用程序严重依赖Internet访问;客户端设备不能在没有与服务器的正确连接和服务器的认证的情况下执行其任何基本功能。真的和Facebook没什么不同。

现在,攻击者想要的计算机是你的服务器,因为它而不是客户端应用程序/设备是可以让他赚钱或让其他人痛苦的东西。没关系;与试图保护所有客户机相比,您花费金钱和精力来保护服务器会获得更大的回报。该服务器可以位于各种防火墙和其他电子安全装置的后面,此外,还可以在钢铁、混凝土、钥匙卡/插针访问和24小时视频监控的后面进行物理保护。您的攻击者需要非常老练才能直接访问服务器,而且您应该立即了解这一点。

攻击者所能做的最好的事情就是窃取用户的电话和凭据,并使用客户端的有限权限登录到服务器。如果发生这种情况,就像丢失一张信用卡一样,合法用户应该被指示从他们可以访问的任何电话拨打一个800号码(最好是容易记住的号码,而不是在钱包、钱包或公文包中携带的卡背面,这可能会在移动设备旁边被盗),该电话可以直接连接到您的客户服务。他们声明自己的手机被盗,提供一些基本的唯一标识符,账户被锁定,攻击者可能处理的任何交易都被回滚,攻击者又回到了原点。

当他们在手机上安装该应用程序时,他们可以完全访问该应用程序的内存。因此,如果你想防止它被黑客入侵,你可以尝试将其制作成这样,你就不能通过使用调试器直接获取静态内存地址。如果有地方可以写并且有限制,那么它们可能会发生堆栈缓冲区溢出。所以在他们写东西的时候尽量做到这一点,如果你必须有一个限制,如果他们发送的字符数超过了限制,如果(input>limit)则忽略,这样他们就不能把汇编代码放在那里。

我建议您查看“保护软件应用程序免受攻击”。这是一项商业服务,但我朋友的公司使用了它,他们很高兴使用它。