OBJ-C 在取消它之前擦除 NSData 内容
OBJ-C wipe NSData content before nullifying it
出于安全原因,我们需要始终从内存中擦除敏感数据。
通常这不是我在 IOS 中看到的事情,但对于需要扩展安全性的应用程序来说,这非常重要。
NSData 和 NSString 对象通常需要擦除的数据(指向 nil 不会擦除数据,这是一个安全漏洞)
我已经成功地用下面的代码擦除我的 NSStrings(当密码是 NSString 时):
unsigned char *charPass;
if (password != nil) {
charPass = (unsigned char*) CFStringGetCStringPtr((CFStringRef) password, CFStringGetSystemEncoding());
memset(charPass, 0, [password length]);
password = nil;
}
- 关于此实现的重要评论:您必须在调用 charPass 之前检查 NULL,否则它可能会崩溃。无法保证 CFStringGetCStringPtr 会 return 一个值!
当密码是 NSData 时它应该更严格,下面的代码应该可以工作:
memset([password bytes], 0, [password length]);
但这给了我一个编译错误:
No matching function for call to 'memset'
我找不到一个解决方法来指向密码地址并擦除那里的字节,就像我对字符串所做的那样(字节方法应该让我按照我的理解来做,但它不会编译一些我无法弄清楚的原因)
有人对此有想法吗?
10 倍
虽然我不能说明这样做的实际安全性,但您的问题是 NSData
的 bytes
方法 returns 和 const void *
https://developer.apple.com/documentation/foundation/nsdata/1410616-bytes?language=objc
如果需要,您可以将其转换为 void *
memset((void *)[password bytes], 0, [password length]);
如果您使用 NSMutableData
,则不必执行此操作。
您的字符串释放器脆弱。你写:
Big remark on this implementation: You HAVE to check for NULL before calling the charPass or it might crash. There is NO guarantee that CFStringGetCStringPtr will return a value!
这是记录在案的行为,因为 CFString
(因此 NSString
)确实 不 保证您可以直接访问其内部缓冲区。你没有说你是如何处理这种情况的,但如果你不擦除记忆,你可能有安全问题。
如果你确实得到了一个有效的指针,你使用了错误的字节数。调用 [password length]
returns:
The number of UTF-16 code units in the receiver.
这和字节数不一样。然而 CFStringGetCStringPtr
returns:
A pointer to a C string or NULL if the internal storage of theString does not allow this to be returned efficiently.
如果你有一个 C 字符串,你可以使用 C 库函数 strlen()
来计算它的长度。
要解决 CFStringGetCStringPtr
returns NULL
的情况,您可以自己将字符串创建为 CFString
并提供自定义 CFAllocater
。您不需要自己编写一个完整的分配器,而是可以基于系统构建一个。您可以获得默认分配器 CFAllocatorContext
,它将 return 您系统使用的函数指针。然后,您可以基于 CFAllocatorContext
创建一个新的 CFAllocator
,它是默认值的副本,除非您更改了指向您拥有的函数的 deallocate
和 reallocate
指针根据默认 allocate
、reallocate
和 deallocate
实现,但也会适当地调用 memset
来清除内存。
完成后,安全擦除将归结为确保这些自定义创建的 CFString
对象,又名 NSString
对象,在您的应用程序退出之前被释放。
您可以在 Memory Management Programming Guide for Core Foundation.
中找到有关 CFAllocator
、CFAllocatorContext
等的信息
这让我们想到了您的实际问题,如何将 NSData
归零。幸运的是,NSData
对象是一个 CFData
对象,并且 CFData
的 CFDataGetBytePtr
与 CFStringGetCStringPtr
不同,它保证 return指向实际字节的指针,直接来自文档:
This function is guaranteed to return a pointer to a CFData
object's internal bytes. CFData
, unlike CFString
, does not hide its internal storage.
因此,遵循 CFString
模式的代码将在这里工作。请注意,使用 NSData
的 bytes
是 not 在文档中保证调用 CFDataGetBytePtr
,它可以例如调用 CFDataGetBytes
和return 一个 copy 个字节,使用 CFData
函数。
HTH
出于安全原因,我们需要始终从内存中擦除敏感数据。 通常这不是我在 IOS 中看到的事情,但对于需要扩展安全性的应用程序来说,这非常重要。
NSData 和 NSString 对象通常需要擦除的数据(指向 nil 不会擦除数据,这是一个安全漏洞)
我已经成功地用下面的代码擦除我的 NSStrings(当密码是 NSString 时):
unsigned char *charPass;
if (password != nil) {
charPass = (unsigned char*) CFStringGetCStringPtr((CFStringRef) password, CFStringGetSystemEncoding());
memset(charPass, 0, [password length]);
password = nil;
}
- 关于此实现的重要评论:您必须在调用 charPass 之前检查 NULL,否则它可能会崩溃。无法保证 CFStringGetCStringPtr 会 return 一个值!
当密码是 NSData 时它应该更严格,下面的代码应该可以工作:
memset([password bytes], 0, [password length]);
但这给了我一个编译错误:
No matching function for call to 'memset'
我找不到一个解决方法来指向密码地址并擦除那里的字节,就像我对字符串所做的那样(字节方法应该让我按照我的理解来做,但它不会编译一些我无法弄清楚的原因)
有人对此有想法吗?
10 倍
虽然我不能说明这样做的实际安全性,但您的问题是 NSData
的 bytes
方法 returns 和 const void *
https://developer.apple.com/documentation/foundation/nsdata/1410616-bytes?language=objc
如果需要,您可以将其转换为 void *
memset((void *)[password bytes], 0, [password length]);
如果您使用 NSMutableData
,则不必执行此操作。
您的字符串释放器脆弱。你写:
Big remark on this implementation: You HAVE to check for NULL before calling the charPass or it might crash. There is NO guarantee that CFStringGetCStringPtr will return a value!
这是记录在案的行为,因为 CFString
(因此 NSString
)确实 不 保证您可以直接访问其内部缓冲区。你没有说你是如何处理这种情况的,但如果你不擦除记忆,你可能有安全问题。
如果你确实得到了一个有效的指针,你使用了错误的字节数。调用 [password length]
returns:
The number of UTF-16 code units in the receiver.
这和字节数不一样。然而 CFStringGetCStringPtr
returns:
A pointer to a C string or NULL if the internal storage of theString does not allow this to be returned efficiently.
如果你有一个 C 字符串,你可以使用 C 库函数 strlen()
来计算它的长度。
要解决 CFStringGetCStringPtr
returns NULL
的情况,您可以自己将字符串创建为 CFString
并提供自定义 CFAllocater
。您不需要自己编写一个完整的分配器,而是可以基于系统构建一个。您可以获得默认分配器 CFAllocatorContext
,它将 return 您系统使用的函数指针。然后,您可以基于 CFAllocatorContext
创建一个新的 CFAllocator
,它是默认值的副本,除非您更改了指向您拥有的函数的 deallocate
和 reallocate
指针根据默认 allocate
、reallocate
和 deallocate
实现,但也会适当地调用 memset
来清除内存。
完成后,安全擦除将归结为确保这些自定义创建的 CFString
对象,又名 NSString
对象,在您的应用程序退出之前被释放。
您可以在 Memory Management Programming Guide for Core Foundation.
中找到有关CFAllocator
、CFAllocatorContext
等的信息
这让我们想到了您的实际问题,如何将 NSData
归零。幸运的是,NSData
对象是一个 CFData
对象,并且 CFData
的 CFDataGetBytePtr
与 CFStringGetCStringPtr
不同,它保证 return指向实际字节的指针,直接来自文档:
This function is guaranteed to return a pointer to a
CFData
object's internal bytes.CFData
, unlikeCFString
, does not hide its internal storage.
因此,遵循 CFString
模式的代码将在这里工作。请注意,使用 NSData
的 bytes
是 not 在文档中保证调用 CFDataGetBytePtr
,它可以例如调用 CFDataGetBytes
和return 一个 copy 个字节,使用 CFData
函数。
HTH