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

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

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

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

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

  3. 在使用密钥之前,应用程序应该执行密钥值的校验和,以validation未损坏的密钥与代码在构build时声明的值相匹配; 和

  4. 最后,应用程序在应用程序使用完该特定的调用之后,应立即重新损坏内存中的密钥。

find2 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; } 

我之前已经写过关于解决这个问题的挑战 ,但是我想用你的UAObfuscatedString想法来演示一下,因为我认为这是大多数人正在寻找的解决scheme,但是比什么都没有。 重要的是要注意:我并不是特别擅长这一点。 我不是一个经验丰富的逆向工程师,商业系统远远超出了我的技能。 我只是一个有Hopper的人 ,真正做了5分钟的逆向工程(我跑了一个计时器; 5:35,包括升级Hopper,因为我没有在几个月内运行)。

所以,我用UAObfuscatedString编写了一个iOS程序。 我使用了Swift,因为Swift通常比ObjC更难于反向工程。 ObjC是逆向工程师的梦想。

 let identifier = "c".omdot.urbanappsdot.example func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { print(identifier) return true } 

然后我将它归档,所以它是优化的代码等等,就像你发送到App Store一样。 然后我把它加载到Hopper中,并查看应用程序委托的init 。 这就是常量被初始化的地方,这是基于大多数人把这些东西放在他们的应用代理中的假设。 显然,如果我看到一个名为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方法,我search并find使用混淆string的应用程序中的任何地方。 如果我愿意把自己的游戏做一点点,花上一天左右的时间,我可以编写一个工具,使用otool和二进制文件自动提取每个UAObfuscatedString

这是深刻的教训。 你刚刚标记了你想隐藏的所有string。 一旦我意识到UAObfuscatedString是一件事情,你只是让我更容易find你的敏感信息。 这实际上比没有更糟。 你唯一的希望就是攻击者不知道这个存在。 这就是混淆的问题,以及混淆与安全的区别。

我还要强调,我花了5分35秒攻击这个节目。 是的,我基本上知道我在找什么样的东西,但我也没有这方面的技能。 如果UAObfuscatedString变得stream行起来,我向你保证,自动检测/去混淆工具将成为每个脚本 – 小孩的工具箱的一部分(“脚本 – 小孩”是安全人员所谓的不知道他们在做什么的攻击者,并只使用其他人写的自动化工具)。

这里的教训是,如果你想混淆,你最好自己编写一些随机的方法。 这将不会有效,但它可能不会以大多数FOSS解决scheme的方式对您的目标产生积极的危害。 “自由和开放源代码”对于安全来说可能是非常好的,但对于默默无闻的事情却是最糟糕的事情。

如果隐藏信息对您的业务计划非常重要,并且您不能改变您的业务计划,那么您应该期望在这个问题上花费大量资金,聘请一个专门致力于不断改进您的混淆系统的团队,以保持领先攻击者将适应你所build立的任何东西。

所以我build议使用你的第二个发现

https://github.com/UrbanApps/UAObfuscatedString

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

所以所有的方法都可以在后面的代码中使用keychain中的值。 也build议build立一个单身人士,将提供访问这些值也保持一个时间,你想改变或更新这个解决scheme

一般来说,我写了可能API代码内联键,有时声明他们分为两部分安全。 我正在使用一个大脑因素;)

让我们说你的API密钥xxx-xxxx-xxxx我编码的stringxxx-xxxx-xFFF,正如你所看到的,与右键相同的长度,在其他方法的某处,我剪切las FFF,并追加右xxx后缀。

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

您可以分别将密码保存在encryption光盘上的文件或encryption的USB记忆棒上。 您的代码将从安全存储中检索相应的文件。 所有攻击者都会在你的代码中看到密码文件的名字。

如果这是不实际的,那么你可以在你的代码中encryption密码。 您的应用程序将包含文本string,如:“请input您的密码”。 这看起来不像一个密钥,但是您可以使用该string作为XOR密钥来encryption/解密密码。 攻击者会看到您在代码中使用的XOR键,并且能够自己解密,因此这更加脆弱。

无论使用什么方法,都要记住在超出范围之前覆盖保存实际密码的variables。