保护字符串常量免受反向工程攻击

26

我有一个Android应用程序,其中硬编码(静态字符串常量)凭据(用户/密码)用于通过SMTP发送电子邮件。

问题在于,.apk中的.dex文件可以很容易地被反向工程化,每个人都可以看到我的密码。

是否有一种方法可以保护这些凭据,同时我仍然能够在我的类中使用它们?


2
为什么不对它们进行哈希处理? - Richard H
@Richard H,我认为如果他需要重复使用凭证,哈希是不可能的吧? - user802421
如果他已经对它们进行了哈希,那么他如何取消哈希登录/密码以将其发送到SMTP服务器?如果它是双向函数,那么很容易解密。如果它是需要盐/密钥的哈希,则他也需要对其进行哈希。甚至有一个关于将DEX反编译为源代码的线程。 - Y.A.P.
@Y.A.P - 是的,抱歉我没有意识到需要双向加密。 - Richard H
9个回答

6
我们可以使用"jni模块"来保留应用程序中的“敏感硬编码字符串”。当我们尝试反向工程APK文件时,会得到相应进程文件夹中的lib文件夹和.so文件,这些文件是无法解密的。

2
我仍然可以在.so文件中看到字符串。 - Grishma Ukani

4
你可以使用AES来混淆你的字符串。
在许可验证库中,你可以找到AES混淆器。在LVL中,它被用于混淆缓存的许可证信息,而不是询问Android市场是否已经获得了应用程序的许可证。LVL可以作为SDK的组件下载。

3

我猜你可以尝试使用代码混淆器,但实际上这并不能使你的密码100%安全,而且我不知道它与Android编译器的兼容性如何。为什么不使用像Google一样的安全Web身份验证呢?


2
我认为混淆器不会改变字符串的内容(凭证)。需要先加密内容。但正如你所说,最好使用Web身份验证。 - user802421
ProGuard(Android SDK默认提供的混淆工具)不会加密或混淆字符串。DexGuard可以加密字符串,但价格有点高。 - AxeEffect

2

以下操作会很有用:

1- 您可以加密它们并混淆加密算法。任何加密与混淆(在Adnroid中使用progaurd)都是有用的。

2- 最好将字符串作为字节数组硬编码到您的代码中。许多反向工程应用程序可以获取您的硬编码字符串列表并猜测它们是什么。但当它们以字节数组形式存在时,它们是不可读的。但是,Proguard仍然是必要的。(它仅从RAM字符串常量搜索中隐藏,并且它们仍然可以从.class文件中搜索)

3- 如果在硬编码之前对它们进行加密并使用C++代码解密,则使用C ++ 代码托管您的常量并不是一个坏主意。

这里还有一篇很棒的文章:

https://rammic.github.io/2015/07/28/hiding-secrets-in-android-apps/


2
  1. 散列不可逆,因此无法进行散列。
  2. 任何加密方法,例如AES、DES、Blowfish等都不是可行的解决方案,因为您必须在应用程序中包含解密部分,这可以通过apktool、dex2jar和JD(Java反编译器)的组合进行反编译,这是一种非常强大的组合,可以反编译任何apk文件。
  3. 即使代码混淆器也没有做任何事情,只是让反编译的人的生活变得更加困难,但他最终还是会得到它。

我认为唯一可能有效的方法是将凭据托管在仅您的应用程序可以通过某种单独的身份验证通过Web服务调用访问的服务器上 - 类似于FB的哈希键。 如果它对他们有用,那么对我们也应该有用。


10
这引出了一个问题,即服务器如何区分“只有您的应用程序”访问和黑客的访问。 - Eugene Mayevski 'Callback
3
没错,你又卡住了——往这边走。 - Yugal Jindle
@EugeneMayevski'EldoSCorp 有任何改进吗? - iraycd

2

很棒的链接!那是一个非常有趣的想法。 - Freedom_Ben

1

如果您没有进行Web授权的手段,您将需要在应用程序中包含第三方解密。

以下是您可以尝试的方法: 1)编写一个独立的程序,仅用于创建一次性密码哈希值。(此程序不应是您应用程序的一部分)。记下生成的哈希值。 http://www.mindrot.org/projects/jBCrypt/

 // Hash a password for the first time.
    String hashed = BCrypt.hashpw(password, BCrypt.gensalt(12));

2) 将此密码哈希作为字符串常量存储在您的 APK 中。

3) 然后每次需要检查密码时,使用 bcrypt 与哈希密码进行比较。

// Check that an unencrypted password matches one that has
// previously been hashed
if (BCrypt.checkpw(candidate, hashed))
    System.out.println("It matches");
else
    System.out.println("It does not match");

jBCrypt是一个单一的Java文件,可以直接包含在您的应用程序中。它被认为是密码加密算法中最强大的之一。 即使解密算法存在于您的APK中,试图破解它也非常耗时,详情请参阅下面的文章。

阅读此文章以了解bcrypt的详细信息和安全性。
http://codahale.com/how-to-safely-store-a-password/

再次强调,只有在没有进行基于Web的身份验证的手段时才使用此方法。


但他似乎需要原始pwd而不是已哈希的pwd来进行smtp身份验证。我们该如何翻转这个过程? - Ashok Goli
candidate 字符串怎么样?我是不是漏掉了什么,或者这个答案没用。 - AxeEffect

0

你可以百分之百地保护你的硬编码字符串。

首先,不要使用 pro-guard,而是使用 allatori。

链接:http://www.allatori.com/

其次,不要将硬编码字符串存储在任何变量中,只需像这样使用该字符串:

if(var=="abc"){}

"abc" 是一个硬编码字符串的例子。

Allatori 可以完全混淆像上面代码中使用的所有字符串。

希望对您有所帮助。


0

使用某种只有你(和你的代码)能理解的简单加密或密码。将字符串反转,将其存储为整数数组,其中需要取217的模数或其他愚蠢的数字才能找到真正的密码。


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