我有一些敏感数据想在使用后直接清除。目前,敏感数据采用 NSString 形式。NSString 在我的理解中是不可变的,这意味着我无法真正清除数据。不过,NSMutableString 似乎更合适,因为它是可变的并且具有诸如 replaceCharactersInRange 和 deleteCharactersInRange 之类的方法。我不知道实现细节,所以我想知道 NSMutableString 是否能达到我的目的?
4 回答
我担心 NSMutableString 会尝试优化并将字符串留在内存中。如果你想要更多的控制尝试分配你自己的内存,然后用它创建一个 NSString 。如果这样做,您可以在释放内存之前覆盖它。
char* block = malloc(200);
NSString* string = [[NSString alloc] initWithBytesNoCopy:length:encoding:freeWhenDone];
//use string
memset(block, 0, 200);// overwrite block with 0
[string release];
free(block);
您需要使用 memset 函数用零擦除 c 指针,但是编译器可以优化 memset 调用,请参阅在 iOS 中清除内存中敏感数据的正确方法是什么?
所以代码可能是这样的:
NSString *string = @"hi";
unsigned char *stringChars = (unsigned char *)CFStringGetCStringPtr((CFStringRef)string, CFStringGetSystemEncoding());
safeMemset(stringChars, 0, [string length]);
但要小心清除 NSString 的底层 c 指针。例如,在设备上,如果字符串包含单词“password”,则底层 c 指针只会重用或指向与系统使用的地址相同的地址,并且尝试擦除该内存区域会导致崩溃。
为了安全起见,您可能希望使用 char 数组而不是 char 指针来存储敏感字符串并在之后擦除它们,而无需将其放入 NSString 对象中。
如果攻击者可以读取内存中的内容,那么您将无所适从。
-release
字符串并完成它。无法知道您是否删除了各种缓存中字符串的任何可能副本(例如,如果您将其绘制到屏幕上等)。
您可能需要担心更重要的安全问题。
从 iOS9 开始,从下面的代码片段中获取的 NSString 的内部指针已变为只读,并在尝试设置字节时产生错误访问。
unsigned char *stringChars = (unsigned char *)CFStringGetCStringPtr((CFStringRef)string, CFStringGetSystemEncoding());
NSMutableString 是可能的,但是如果你有另一个 NSString 源,比如来自文本字段,那个源仍然会在内存中,你仍然不走运。
如果您正在创建一个新的 NSString,最好的方法是使用底层字节数组实现您自己的 String 类。提供一种使用底层字节数组作为内部指针创建 NSString 副本的方法。:
-(NSString *)string
{
return [[NSString alloc] initWithBytesNoCopy:_buff length:_length encoding:NSUTF8StringEncoding freeWhenDone:NO];
}
// Will prematurely wipe data and all its copies when called
- (void)clear
{
// Volatile keyword disables compiler's optimization
volatile unsigned char *t = (unsigned char *)_buff;
int len = _length;
while (len--) {
*t++ = 0;
}
}
// In case you forget to clear, it will cleared on dealloc
- (void)dealloc
{
[self clear];
free(_buff);
}