了解sprintf(...)的危险

Kev*_*ith 22 c++ printf

OWASP说:

"诸如strcpy(),strcat(),sprintf()和vsprintf()之类的C库函数对空终止字符串进行操作,并且不执行边界检查."

sprintf将格式化数据写入字符串int sprintf(char*str,const char*format,...);

例:

sprintf(str, "%s", message); // assume declaration and 
                             // initialization of variables
Run Code Online (Sandbox Code Playgroud)

如果我理解OWASP的评论,那么使用sprintf的危险就是那样

1)如果消息的长度> str的长度,则存在缓冲区溢出

2)如果消息没有以null结尾\0,则消息可能被复制到超出消息内存地址的str,导致缓冲区溢出

请确认/否认.谢谢

str*_*ger 24

你在这两个问题上都是正确的,尽管它们实际上都是同一个问题(访问超出数组边界的数据).

第一个问题的解决方案是使用std::snprintf,它接受缓冲区大小作为参数.

第二个问题的解决方案是给出一个最大长度参数snprintf.例如:

char buffer[128];

std::snprintf(buffer, sizeof(buffer), "This is a %.4s\n", "testGARBAGE DATA");

// std::strcmp(buffer, "This is a test\n") == 0
Run Code Online (Sandbox Code Playgroud)

如果要存储整个字符串(例如,在案例sizeof(buffer)中太小),请运行snprintf两次:

int length = std::snprintf(nullptr, 0, "This is a %.4s\n", "testGARBAGE DATA");

++length;           // +1 for null terminator
char *buffer = new char[length];

std::snprintf(buffer, length, "This is a %.4s\n", "testGARBAGE DATA");
Run Code Online (Sandbox Code Playgroud)

(您可以将其放入使用的函数中va.)

  • 当`snprintf'只解决第一个问题时,他们是如何"同时解决问题的?" (4认同)

Joh*_*ing 10

你的两个断言都是正确的.

还有一个未提及的问题.没有类型检查参数.如果格式字符串和参数不匹配,可能会导致未定义和不良行为.例如:

char buf[1024] = {0};
float f = 42.0f;
sprintf(buf, "%s", f);  // `f` isn't a string.  the sun may explode here
Run Code Online (Sandbox Code Playgroud)

这对于调试来说尤其令人讨厌.

所有这些导致许多C++开发人员得出结论,你永远不应该使用sprintf它和它的兄弟.实际上,您可以使用一些设施来避免上述所有问题.一,流,内置于语言:

#include <sstream>
#include <string>

// ...

float f = 42.0f;

stringstream ss;
ss << f;
string s = ss.str();
Run Code Online (Sandbox Code Playgroud)

...对于像我这样仍然喜欢使用的人来说,另一个受欢迎的选择sprintf来自boost格式库:

#include <string>
#include <boost\format.hpp>

// ...

float f = 42.0f;
string s = (boost::format("%1%") %f).str();
Run Code Online (Sandbox Code Playgroud)

你应该采用"从不使用sprintf"的咒语吗?自行决定.通常有一个最好的工具,取决于你正在做什么,sprintf也许就是这样.