将空字符添加到非空终止字符串有什么问题?
What is wrong with adding null character to non null-terminated string?
为什么我不应该像 answer 那样在非空终止字符串的末尾添加空字符?我的意思是,如果我有一个非 null 终止的字符串并在字符串的末尾添加 null 字符,我现在有一个 null 终止的字符串,这应该很好,对吧?
有没有我没看到的安全问题?
以下是防止答案被删除的代码:
char letters[SIZE + 1]; // Leave room for the null-terminator.
// ...
// Populate letters[].
// ...
letters[SIZE] = '[=10=]'; // Null-terminate the array.
要知道字符串的结尾你必须有一个以空字符结尾的字符串,否则无法知道字符串的结尾
以这种方式用 [=10=]
终止字符串在技术上没有任何错误。但是,您可以用来填充数组 before 添加 [=10=]
的方法很容易出错。看看一些情况:
假设您决定逐个字符填充 letters
个字符。如果您忘记添加一些字母会怎样?如果您添加的字母多于预期大小怎么办?
如果有数千个字母填充数组怎么办?
如果您需要用 Unicode 字符填充 letters
,而这些字符(通常)每个符号需要一个字节以上,该怎么办?
当然你可以非常小心地处理这些情况,但在维护代码时它们仍然容易出错。
明确一点:C always 中的 string 有一个且只有一个空字符 - 它是字符串的最后一个字符.字符串是字符数组。如果字符数组没有空字符,则它不是字符串。
A string is a contiguous sequence of characters terminated by and including the first null character. C11dr 7.1.1 1
在 OP 编码的字符数组中添加空字符没有错。
如果满足以下条件,这是形成字符串的好方法:
前面的字符全部定义。
直到写入空字符后才调用字符串函数。
一般来说,有两种方法可以跟踪一些可变数量的事物的数组:
- 使用终止符。当然,这是表示字符串的 C 方法:一些未知大小的字符数组,实际字符串长度由空终止符给出。
- 使用存储在其他地方的显式计数。 (碰巧,这就是 Pascal 传统上表示字符串的方式。)
如果您有一个包含已知但不是以 null 终止的字符序列的数组,并且如果您想将它变成一个适当的以 null 终止的字符串,并且如果您知道底层数组分配得足够大包含空终止符,那么是的,明确地将 array[N]
设置为 '[=11=]'
不仅是可以接受的,而且是 的方法。
底线:这是一项很好的技术(如果满足约束条件)。我不知道为什么之前的回答受到批评和否决。
您不应该使用它,以避免因混合 C/Pascal 字符串而导致的错误(或安全漏洞)。
- C 风格字符串:char 数组,以 NULL ('\0') 结尾
- Pascal 风格的字符串:一种结构,带有一个表示字符串大小的整数,以及一个包含字符串本身的数组。
Pascal 风格不使用in-band control,所以它可以使用其中的任何字符,比如NULL。 C 字符串不能,因为它们将其用作信号控制。
问题是当您将它们混合使用时,或者当它是另一种时采用一种风格。或者甚至尝试在它们之间进行转换。
将 C 字符串转换为 Pascal 不会有任何坏处。但是,如果您有一个包含多个 NULL 字符的合法 Pascal 字符串,将其转换为 C 样式会导致问题,因为它无法表示它。
一个很好的例子是 X.509 Null Char Exploit,您可以在其中注册一个 ssl 证书到:
www.mysimplesite.com[=10=]www.bigbank.com
X.509 证书使用 Pascal 字符串,因此有效。但是在检查时,CA 可以使用或假定只看到第一个 www.mysimplesite.com
并签署证书的 C 代码或字符串样式。一些兄弟将此证书解析为对 www.bigbank.com
.
也有效
因此,您可以使用它,但您应该不,因为它有导致错误甚至安全漏洞的风险.
更多详情和信息:
https://www.blackhat.com/presentations/bh-usa-09/MARLINSPIKE/BHUSA09-Marlinspike-DefeatSSL-SLIDES.pdf
https://sites.google.com/site/cse825maninthemiddle/odds-and-ends/x-509-null-char-exploit
为什么我不应该像 answer 那样在非空终止字符串的末尾添加空字符?我的意思是,如果我有一个非 null 终止的字符串并在字符串的末尾添加 null 字符,我现在有一个 null 终止的字符串,这应该很好,对吧? 有没有我没看到的安全问题?
以下是防止答案被删除的代码:
char letters[SIZE + 1]; // Leave room for the null-terminator.
// ...
// Populate letters[].
// ...
letters[SIZE] = '[=10=]'; // Null-terminate the array.
要知道字符串的结尾你必须有一个以空字符结尾的字符串,否则无法知道字符串的结尾
以这种方式用 [=10=]
终止字符串在技术上没有任何错误。但是,您可以用来填充数组 before 添加 [=10=]
的方法很容易出错。看看一些情况:
假设您决定逐个字符填充
letters
个字符。如果您忘记添加一些字母会怎样?如果您添加的字母多于预期大小怎么办?如果有数千个字母填充数组怎么办?
如果您需要用 Unicode 字符填充
letters
,而这些字符(通常)每个符号需要一个字节以上,该怎么办?
当然你可以非常小心地处理这些情况,但在维护代码时它们仍然容易出错。
明确一点:C always 中的 string 有一个且只有一个空字符 - 它是字符串的最后一个字符.字符串是字符数组。如果字符数组没有空字符,则它不是字符串。
A string is a contiguous sequence of characters terminated by and including the first null character. C11dr 7.1.1 1
在 OP 编码的字符数组中添加空字符没有错。
如果满足以下条件,这是形成字符串的好方法:
前面的字符全部定义。
直到写入空字符后才调用字符串函数。
一般来说,有两种方法可以跟踪一些可变数量的事物的数组:
- 使用终止符。当然,这是表示字符串的 C 方法:一些未知大小的字符数组,实际字符串长度由空终止符给出。
- 使用存储在其他地方的显式计数。 (碰巧,这就是 Pascal 传统上表示字符串的方式。)
如果您有一个包含已知但不是以 null 终止的字符序列的数组,并且如果您想将它变成一个适当的以 null 终止的字符串,并且如果您知道底层数组分配得足够大包含空终止符,那么是的,明确地将 array[N]
设置为 '[=11=]'
不仅是可以接受的,而且是 的方法。
底线:这是一项很好的技术(如果满足约束条件)。我不知道为什么之前的回答受到批评和否决。
您不应该使用它,以避免因混合 C/Pascal 字符串而导致的错误(或安全漏洞)。
- C 风格字符串:char 数组,以 NULL ('\0') 结尾
- Pascal 风格的字符串:一种结构,带有一个表示字符串大小的整数,以及一个包含字符串本身的数组。
Pascal 风格不使用in-band control,所以它可以使用其中的任何字符,比如NULL。 C 字符串不能,因为它们将其用作信号控制。
问题是当您将它们混合使用时,或者当它是另一种时采用一种风格。或者甚至尝试在它们之间进行转换。
将 C 字符串转换为 Pascal 不会有任何坏处。但是,如果您有一个包含多个 NULL 字符的合法 Pascal 字符串,将其转换为 C 样式会导致问题,因为它无法表示它。
一个很好的例子是 X.509 Null Char Exploit,您可以在其中注册一个 ssl 证书到:
www.mysimplesite.com[=10=]www.bigbank.com
X.509 证书使用 Pascal 字符串,因此有效。但是在检查时,CA 可以使用或假定只看到第一个 www.mysimplesite.com
并签署证书的 C 代码或字符串样式。一些兄弟将此证书解析为对 www.bigbank.com
.
因此,您可以使用它,但您应该不,因为它有导致错误甚至安全漏洞的风险.
更多详情和信息: https://www.blackhat.com/presentations/bh-usa-09/MARLINSPIKE/BHUSA09-Marlinspike-DefeatSSL-SLIDES.pdf https://sites.google.com/site/cse825maninthemiddle/odds-and-ends/x-509-null-char-exploit