【问题标题】:Android Java: can switch statement avoid inlining when creating a secret string?Android Java:创建秘密字符串时,switch语句可以避免内联吗?
【发布时间】:2014-08-29 11:50:36
【问题描述】:

我的 Android 应用程序必须在运行时通过连接字符串常量来构建一个秘密字符串。我想避免内联最终字符串,因此无法从 apk 中看到它。假设我有以下两个功能:

private String getConst(int i) {
    switch (i) {
        case 1:
            return getHardCodedConst(1);

        case 2:
            return getHardCodedConst(2);

        case 3:
            return getHardCodedConst(3);

        default:
            break;
    }
}

private String getHardCodedConst(int i) {

    final static String CONST1 = "const1";
    final static String CONST2 = "const2";
    final static String CONST3 = "const3";

    switch (i) {
        case 1:
            return CONST1;

        case 2:
            return CONST2;

        case 3:
            return CONST3;

        default:
            break;
    }
}

以下两个语句是否内联?一个比另一个好?

myString = getConst(1) + getConst(2) + getConst(3);

myString = getHardCodedConst(1) + getHardCodedConst(2) + getHardCodedConst(3);

我的代码不是那么简单,其他技巧掩盖了真正发生的事情,但这是一个重要的问题,因为如果两个语句被内联,我不知道如何避免字符串被盗。

【问题讨论】:

  • 我完全不明白你这样做的目的。为什么你还有getHardCodedConst() 方法?为什么不直接返回常量?它根本没有区别,你这样做唯一得到的就是更混乱的代码。
  • 为什么不直接从第一种方法返回 CONST 呢?第二个需要什么?
  • 通过反汇编可以在 APK 中找到已编译的 Java 代码 - 您将需要使用另一种技术来处理您的安全性(在您使用 OAuth 2.0 对用户进行身份验证后进行某种客户端/服务器交互? )
  • 那么编译器知道getConst() 中可能发生的一切吗?当其他一些事情可能发生时,它如何决定内联?它是否检查方法以查看只有 switch 语句起作用?如果我输入一个在编译时不可用的参数怎么办?我认为在其他地方使用参数集很好。不是吗?还是编译器会费心去发现我设置它的位置?
  • @P5music 是的,编译器知道一切,毕竟是编译器将您的代码转换为字节码。而且,如果您对值进行硬编码,那么在何处或如何定义变量都没有关系,而不是在您的代码中简单明了地供所有人查看。有人要做的就是对您的 APK 进行逆向工程。

标签: java android string constants inline


【解决方案1】:

我想避免内联最终字符串,这样就无法从 APK。

但是你并没有仅仅通过将常量移动到另一种方法来隐藏它们,你所做的只有一个效果:它会让你的代码无缘无故地变得更加混乱。实际上,您尝试做的事情是不可能的。不管您做什么,您的代码中的所有值都可以从您的反向工程 APK 中读取,并且没有没有办法可以防止这种情况发生。你只能通过obfuscation 来增加难度。

以下两个语句是否内联?是不是比 其他的?

两者完全相等,根本没有区别。如果您想改进这部分,请执行以下操作:

// Declare these as constant fields
private final static String CONST1 = "const1";
private final static String CONST2 = "const2";
private final static String CONST3 = "const3";

...

// Use these constant fields directly to build your String
myString = CONST1 + CONST2 + CONST3; 

或者更好的是,这样做:

// Declare this as constant fields
private final static String CONST1 = "const1";
private final static String CONST2 = "const2";
private final static String CONST3 = "const3";

// Since the resulting String is build from constants it is itself also a constant
// This means we can also declare it as a constant field:
private final static String MY_STRING = CONST1 + CONST2 + CONST3;

如果您不需要单独使用 CONST1CONST2CONST3,那么只需执行以下操作:

private final static String MY_STRING = "const1const2const3";

所有这些改进只是为了让您的代码保持干净、可维护和可读。除此之外,它完全没有区别。无论您如何或在何处定义 Strings,该程序都将以完全相同的方式运行,但按照我的建议进行操作可以使代码简单易懂 - 顺便说一句,这应该是优秀程序员的首要任务。

实施我上面的建议可能会带来微不足道的性能提升,因为您不需要调用任何方法,因此开销可能会更少。仅访问字段非常快。


仅供参考:如果您想将敏感或重要信息存储在安全位置,只有一种方法:将其存储在服务器上并通过网络服务访问。

【讨论】:

  • 我只关心内联,我使用其他技巧但我必须避免内联。运行时设置的参数对在 switch 语句中欺骗编译器有用吗?
  • 为什么一定要避免呢?你希望避免它会发生什么?我告诉你没有区别。你只是在完全没有理由让你的代码变得复杂。正如我在回答中所述没有办法阻止任何人从您的 apk 中读取数据。你在做什么是没有用的。反过来想象一下:当你编译你的应用程序并且无论你做什么都会生成字节码,无论是内联还是避免内联都没有关系,如果你添加一个像getHardCodedConst()这样的无用方法,那么编译器将优化无论如何它都会消失。
  • 我再说一遍:您无法阻止任何人从您的 apk 中窃取信息,并且您对代码所做的任何事情都不会影响其他人窃取数据的能力。如果他们想要它,那么即使您混淆了,他们也可以得到它。保证敏感数据安全的唯一方法是将它们存储在应用程序之外的服务器上,并通过网络服务访问它。
  • @P5music 你真的需要更多地研究混淆,enough tools 可以混淆字符串。如果您可以手动完成,那么混淆器可以为您完成。
  • 我什至不明白你所说的“内联”是什么意思。我可以再次重申:无论你做什么对编译的 APK 没有任何影响,你可以编写 1000 个无用的方法和 500 个变量,并将你的代码分成任意多的部分,但所做的只是让你的代码更复杂,它不会改变 APK 的任何内容。我再说一遍:你不能阻止任何人从你的 APK 中读取数据,混淆只会让事情变得更难。
猜你喜欢
  • 2013-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多