2017-06-22 100 views
2

在我的Objective C代码中,我的代码中有一个使用者密钥和密码,用于SHA-1加密。我想知道的是我是否可以避免硬编码来提高安全性。我发现有以下几种到目前为止,如何避免硬编码加密密钥(目标C)?

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

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

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

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

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

找到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; 
} 
+1

你是什么意思“破坏”一个关键?假设密钥是一个字符串:如何“损害”一个字符串? – Sajjon

+1

如果您正在寻找一种在iOS应用程序中安全存储密钥(例如字符串)的方法,则应将其存储在“KeyChain”中。请参阅https://www.raywenderlich.com/92667/securing-ios-data-keychain-touch-id-1password或者可能是开源框架:https://github.com/kishikawakatsumi/KeychainAccess – Sajjon

+1

,你应该清楚你究竟在试图抵御自己的攻击,你害怕什么类型的攻击。 – luk2302

回答

4

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

所以,我写了一个iOS程序UAObfuscatedString。我使用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。这就是常量初始化的地方,这是基于大多数人将这些东西放在他们的应用代理中的假设。显然,如果我看到一个名为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 

我不知道为什么斯威夫特demangler不在这里工作,但无论如何,我们可以很容易地看到这个模式:

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

意识到有这些USObfuscatedString方法,我寻找的是并在使用混淆字符串的应用中查找无处不在。如果我愿意提升我的游戏并花一天左右的时间玩它,我可能会编写一个工具来自动提取每个UAObfuscatedString,只需使用otool和二进制。

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

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

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

如果隐藏信息对您的业务计划非常重要,并且您无法更改您的业务计划,那么您应该期望在此问题上花费大量资金并聘请一个专门致力于不断改进您的混淆系统的人员团队保持领先攻击者的位置,这些攻击者将适应你的任何构建。

+1

“我使用Swift是因为Swift通常比ObjC更难于进行反向工程“。你能解释一下这是怎么回事?我想详细了解。就我所知,Swift和Objective C使用相同的运行时。 – ViruMax

+3

@virumax Swift具有广泛的静态分派功能,可以内联函数,然后根据这些事情执行优化。这使得得到的Swift与原始代码相比与Objective-C的关系要少得多,而Objective-C无法跨消息传递进行优化(objc_msgSend)。 objc_msg发送调用遍及编译的Objc必然会告诉你方法的名字。这在优化的Swift代码中通常不可用。虽然Swift *可以使用ObjC运行时,但它并不需要,许多Swift也不需要。在这方面,Swift更接近于C++。 –

+0

我并不是说Swift对逆向工程来说特别困难。但Objective-C是一种逆向工程师对于本地编译语言的梦想。 –

1

因此,我建议用你的第二个发现

https://github.com/UrbanApps/UAObfuscatedString

和再生的串在第一应用程序启动

添加到钥匙扣

所以所有的方法都可以稍后在代码中使用钥匙串中的值。 另外我建议建立一个单身人士,将提供访问这些值也保持在一个时间你想改变或更新这个解决方案

在一般情况下,我写了可能api键只是内联在代码中,有时声明他们分裂它分为两部分以确保安全。我正在使用脑因子;)

让我们说你的API密钥xxx-xxxx-xxxx 我编码的字符串xxx-xxxx-xFFF,正如你所看到的,它的长度与右键相同,在其他方法中我切断了las FFF并追加右边的xxx后缀。

如果你有偏执狂,你可以在不同的类中定义同一个文件,但为了方便起见,它们保持按字母顺序排列的不同位置,比如AStoredKeys TheRightPostfixes以某种方式隐藏了反汇编器的方法。

+0

您试图通过存储在钥匙串中实现的任何其他级别的安全性?你的方法和UAObfuscatedString都会在部分代码中仍然有字符串值(尽管很难破解)。 –

+1

'UAObfuscatedString'比这个例子更糟糕。它实际上发光了您想要隐藏的数据,同时不提供任何保护。你的分裂方法要好得多,尽管我可能会以不同的方式做几件事情。使用原始字节而不是字符串(字符串很容易在二进制文件中找到)。将它分割成错误的长度(或填充错误的长度),以便搜索“正确长度的东西”不起作用。并将其与其他一些随机数据进行异或运算,以便实际字节不会出现在二进制文件中。我的方式也没有效果,但至少会尝试。 –

+1

(我们的两种方法都是OWASP提到的“损害”的正确版本,并且通常是在不聘用专门团队的情况下可以做到的最好的版本。) –

-1

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

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

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