如何避免硬编码加密密钥(目标C)?

时间:2017-06-22 09:20:16

标签: ios objective-c security encryption sha1

在我的Objective C代码中,我的代码中有一个消费者密钥和密码,用于SHA-1加密。我想知道的是我是否可以避免硬编码来提高安全性。到目前为止我找到了以下内容,

发现1 https://www.owasp.org/index.php/Technical_Risks_of_Reverse_Engineering_and_Unauthorized_Code_Modification#Cryptographic_Key_Replacement 解释的步骤如下,

  1. 损坏源代码中声明的静态密钥。这些密钥在磁盘上应该被损坏,以防止对手分析和拦截原始密钥;

  2. 接下来,应用程序应该在需要密钥的代码使用它之前修复密钥;

  3. 在使用密钥之前,应用程序应立即执行密钥值的校验和,以验证未损坏的密钥是否与代码在构建时声明的值相匹配;以及

  4. 最后,在应用程序完成对特定呼叫的使用后,应用程序应立即重新损坏内存中的密钥。

  5. 发现2 https://github.com/UrbanApps/UAObfuscatedString

    有人可以帮帮我吗?

    示例代码:

    + (NSString *) getOauthHeaderForRequestString:(NSString *)requestString {
    
    NSString *oauthConsumerKey = @"<consumer key which I want avoid hardcoding>";
    NSString *oauthConsumerSecret = @"<consumer secret which I want to avoid hardcoding>";
    NSString *oauthSignatureMethod = @"HMAC-SHA1";
    NSString *oauthVersion = @"1.0";
    
    NSString *oauthNonce = [self generateNonce];
    NSString *oauthtimestamp = [NSString stringWithFormat:@"%d", (int)[[NSDate date] timeIntervalSince1970]];
    
    NSArray * params = [NSArray arrayWithObjects:
                        [NSString stringWithFormat:@"%@%%3D%@", @"oauth_consumer_key", oauthConsumerKey],
                        [NSString stringWithFormat:@"%@%%3D%@", @"oauth_nonce", oauthNonce],
                        [NSString stringWithFormat:@"%@%%3D%@", @"oauth_signature_method", oauthSignatureMethod],
                        [NSString stringWithFormat:@"%@%%3D%@", @"oauth_timestamp", oauthtimestamp],
                        [NSString stringWithFormat:@"%@%%3D%@", @"oauth_version", oauthVersion],
                        [NSString stringWithFormat:@"%@%%3D%@", @"request", [requestString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]],
                        nil];
    
    params = [params sortedArrayUsingSelector:@selector(compare:)];
    NSString *parameters = [params componentsJoinedByString:@"%26"];
    
    NSString *postURL = @"<my post url>";
    
    NSArray * baseComponents = [NSArray arrayWithObjects:
                                @"POST",
                                [self encodeString:postURL],
                                parameters,
                                nil];
    NSString * baseString = [baseComponents componentsJoinedByString:@"&"];
    
    NSArray *signingKeyComponents = [NSArray arrayWithObjects:oauthConsumerSecret, @"", nil];
    NSString *signingKey = [signingKeyComponents componentsJoinedByString:@"&"];
    
    NSData *signingKeyData = [signingKey dataUsingEncoding:NSUTF8StringEncoding];
    NSData *baseData = [baseString dataUsingEncoding:NSUTF8StringEncoding];
    
    uint8_t digest[20] = {0};
    CCHmac(kCCHmacAlgSHA1, signingKeyData.bytes, signingKeyData.length, baseData.bytes, baseData.length, digest);
    
    NSData *signatureData = [NSData dataWithBytes:digest length:20];
    
    NSString *oauthSignature = [self base64forData:signatureData];
    
    // final request build
    NSString *oauthHeader = @"OAuth ";
    oauthHeader = [oauthHeader stringByAppendingFormat:@"oauth_consumer_key=\"%@\"",oauthConsumerKey];
    oauthHeader = [oauthHeader stringByAppendingFormat:@",oauth_nonce=\"%@\"",oauthNonce];
    oauthHeader = [oauthHeader stringByAppendingFormat:@",oauth_signature=\"%@\"",[self encodeString:oauthSignature]];
    oauthHeader = [oauthHeader stringByAppendingFormat:@",oauth_signature_method=\"%@\"",oauthSignatureMethod];
    oauthHeader = [oauthHeader stringByAppendingFormat:@",oauth_timestamp=\"%@\"",oauthtimestamp];
    oauthHeader = [oauthHeader stringByAppendingFormat:@",oauth_version=\"1.0\""];
    
    return oauthHeader;
    }
    

4 个答案:

答案 0 :(得分:9)

我已经写过关于the challenges of solving this problem before的文章,但我想用UAObfuscatedString想法来展示一点,因为我认为这是大多数人都在寻找的解决方案,但是比什么都没有。值得注意的是:我并不是特别擅长这一点。我不是经验丰富的逆向工程师,商业系统超出了我的技能。我只是一个Hopper和五分钟逆向工程的人(我跑了一个计时器; 5:35s,包括升级Hopper因为我几个月没有运行它)。

所以,我用UAObfuscatedString编写了一个iOS程序。我使用Swift是因为Swift通常比ObjC更难逆向工程。 ObjC is a reverse engineer's dream.

let identifier = "c".o.m.dot.u.r.b.a.n.a.p.p.s.dot.e.x.a.m.p.l.e

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    print(identifier)
    return true
}

然后我将其归档,以及它的优化代码等等,就像您发送到App Store一样。然后我将其加载到Hopper并查看了应用代表的init。基于大多数人将这些东西粘贴在他们的app委托中的假设,初始化常量的地方。显然,如果我看到一个名为KeyStorageSecretStuffHelper的课程,我会先看一下......

void * -[_TtC13ObfuscateTest11AppDelegate init](void * self, void * _cmd) {
    *(r31 + 0xffffffffffffffe0) = r20;
    *(0xfffffffffffffff0 + r31) = r19;
    *(r31 + 0xfffffffffffffff0) = r29;
    *(r31 + 0x0) = r30;
    r0 = sub_100005e14();
    return r0;
}

嗯,它称之为匿名函数sub_100005e14()。让我们看看它是做什么的。

...
0000000100005e38         adr        x0, #0x100006859                            ; "c"
...
0000000100005e48         bl         imp___stubs___T0SS18UAObfuscatedStringE1oSSfg
...
0000000100005e50         bl         imp___stubs___T0SS18UAObfuscatedStringE1mSSfg
...
0000000100005e74         bl         imp___stubs___T0SS18UAObfuscatedStringE3dotSSfg
...
0000000100005e98         bl         imp___stubs___T0SS18UAObfuscatedStringE1uSSfg
...
0000000100005ebc         bl         imp___stubs___T0SS18UAObfuscatedStringE1rSSfg
...
0000000100005ee0         bl         imp___stubs___T0SS18UAObfuscatedStringE1bSSfg
...
0000000100005f04         bl         imp___stubs___T0SS18UAObfuscatedStringE1aSSfg
...
0000000100005f28         bl         imp___stubs___T0SS18UAObfuscatedStringE1nSSfg
...
0000000100005f4c         bl         imp___stubs___T0SS18UAObfuscatedStringE1aSSfg
...
0000000100005f70         bl         imp___stubs___T0SS18UAObfuscatedStringE1pSSfg
...
0000000100005f94         bl         imp___stubs___T0SS18UAObfuscatedStringE1pSSfg
...
0000000100005fb8         bl         imp___stubs___T0SS18UAObfuscatedStringE1sSSfg
...
0000000100005fdc         bl         imp___stubs___T0SS18UAObfuscatedStringE3dotSSfg
...
0000000100006000         bl         imp___stubs___T0SS18UAObfuscatedStringE1eSSfg
...
0000000100006024         bl         imp___stubs___T0SS18UAObfuscatedStringE1xSSfg
...
0000000100006048         bl         imp___stubs___T0SS18UAObfuscatedStringE1aSSfg
...
000000010000606c         bl         imp___stubs___T0SS18UAObfuscatedStringE1mSSfg
...
0000000100006090         bl         imp___stubs___T0SS18UAObfuscatedStringE1pSSfg
...
00000001000060b4         bl         imp___stubs___T0SS18UAObfuscatedStringE1lSSfg
...
00000001000060d8          bl         imp___stubs___T0SS18UAObfuscatedStringE1eSSfg

我不确定为什么Swift demangler不在这里工作,但无论如何,我们可以很容易地看到这种模式:

_T0SS18UAObfuscatedStringE1oSSfg => o
_T0SS18UAObfuscatedStringE1mSSfg => m
_T0SS18UAObfuscatedStringE3dotSSfg => dot => .
_T0SS18UAObfuscatedStringE1uSSfg => u
...

实现这些USObfuscatedString方法,我搜索并在应用程序中找到使用混淆字符串的所有方法。如果我愿意花一点时间玩游戏并花一天时间玩它,我可能会编写一个工具,只使用UAObfuscatedString和二进制文件自动提取每个otool

这是深刻的教训。您刚刚标记了要隐藏的所有字符串。一旦我意识到UAObfuscatedString是一件事,你就让我更容易让我找到你的敏感信息。它实际上比什么都没有。你唯一的希望是攻击者不知道这存在。这就是混淆的问题,以及混淆与安全的区别。

我还要强调,我花了5分35秒攻击这个程序。是的,我基本上知道我在寻找什么样的东西,但我也没有这方面的技能。如果UAObfuscatedString变得流行,我向你保证自动检测/去混淆工具将成为每个脚本小子工具箱的一部分(&#34; script-kiddie&#34;是什么安全人员称攻击者不知道他们正在做什么,只使用其他人写过的自动化工具。

这里的教训是,如果你想混淆,你最好自己制定一些随机的方法。它不会有效,但它可能不会像大多数FOSS解决方案那样对你的目标产生积极的伤害。 &#34;免费开源&#34;可以非常有利于安全,但对于默默无闻是最糟糕的事情。

如果隐藏信息对您的商业计划非常重要而且您无法改变您的商业计划,那么您应该花费大量资金解决此问题,并聘请专门致力于不断改进您的混淆的人员团队系统,以保持领先于适应你所建立的任何人的攻击者。

答案 1 :(得分:1)

所以我建议你使用你的第二次发现

  

https://github.com/UrbanApps/UAObfuscatedString

并在第一次启动应用程序时将重新生成的字符串添加到钥匙串

所以所有方法都可以在代码中使用keychain中的值。 我还建议构建一个单例,它可以提供对这些值的访问,也可以将所有值保持在一起,以便您想要更改或更新此解决方案

一般来说,我写的api键可能只是代码内联,有时候声明它们将它分成两部分以保证安全。我正在使用脑因子;)

让我们说API密钥xxx-xxxx-xxxx 我编码字符串xxx-xxxx-xFFF,如你所见,它的长度与右键相同,在其他方法的某个地方,我切割las FFF并附加右xxx后缀。

如果你有偏执狂,你可以在同一个文件中定义的不同类中为方便起见,但保持字母顺序不同的地方,如AStoredKeys TheRightPostfixes,以某种方式隐藏你的方法来反汇编。

答案 2 :(得分:1)

老实说,您无能为力。文字可能是最好的选择,但是请考虑一下,您真的不知道谁将拥有设备以及他们正在使用该设备做什么。可以肯定地说,任何有才华的工程师都可以找到设备上的按键和代码。即使您保护自己的钥匙,也有一些应用程序(例如屏幕抓取器)和其他真正无法获取信息的东西。混淆不是一个好的长期实践,好的工程师可以解决这个问题……这只会减慢他们的速度。您确实可以控制服务器,因此请专注于保持其稳定。

通常,不要考虑保护密钥,而应该考虑更多有关限制信息和访问的问题。

关于数据,尽量减少要接收的私人数据。例如,从不显示信用卡号,仅存储最后4位数字。或者在银行应用程序的情况下,仅显示帐户余额,并且它们还提供两要素身份验证(例如,带有图像)。如果设备受到威胁,虽然知道一个人的平衡会很糟糕,但这不是世界末日。

这也往往是良好的公司惯例,因为它可以使您免受任何指控。如果您一开始没有信息,那么一个人无法声称信息已被泄露。

具有访问权限,限制应用程序的功能。在某种程度上对其进行防火墙。或提供其他身份验证步骤,例如SMS验证,两因素身份验证。您还可以让服务器为您执行安全任务。如果是银行业务,则应限制转账次数或金额,而不是无限次转账。限制可以转移到的帐户。

答案 3 :(得分:-1)

您可以单独保存密码,加密光盘上的文件或加密的USB记忆棒。您的代码只会从安全存储中检索相应的文件。所有攻击者都会在您的代码中看到密码文件的名称。

如果这不切实际,那么您可以对代码中的密码进行XOR加密。您的应用程序将包含如下文本字符串:“请输入您的密码。”这看起来不像是一个密钥,但您可以使用该字符串作为XOR密钥来加密/解密密码。这更容易受到攻击,因为攻击者会在您的代码中看到您正在使用的XOR密钥,并且能够为自己解密。

无论使用哪种方法,都要记得在超出范围之前覆盖保存实际密码的变量。

相关问题