为什么我需要确保 fprintf_s 中的格式不是用户定义的字符串?

Squ*_*red 2 c printf

https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fprintf-s-fprintf-sl-fwprintf-s-fwprintf-sl?view=msvc-170

int fprintf_s(
   FILE *stream,
   const char *format [,
   argument_list ]
);
Run Code Online (Sandbox Code Playgroud)

format 格式控制字符串。

fprintf_s (stdout, "%s", "Hello" );
Run Code Online (Sandbox Code Playgroud)

重要 确保格式不是用户定义的字符串。

这是什么意思?不要这样做:

char user_defined_str [100] = "%s";
fprintf_s (stdout, user_defined_str, "Hello");
Run Code Online (Sandbox Code Playgroud)

?如果“是”——为什么?问题是什么?

我尝试阅读并期待“是”,但不明白为什么应该避免这种情况。

dat*_*olf 5

这里的相关术语是“格式字符串攻击”。

让我们对您的代码进行一些更改

char user_defined_str [100];
fgets(user_defined_str, sizeof(user_defined_str), stdin);
fprintf_s (stdout, user_defined_str, "Hello");
Run Code Online (Sandbox Code Playgroud)

现在假设如果用户提供格式字符串会发生什么%s %s?没有进一步的参数传递给fprintf_s,但该函数不知道这一点。因此它只会尝试从参数上的指针所在的位置打印一个字符串,但在这种情况下它将是一些垃圾值。

这可用于公开进程内的数据,例如不应公开的加密密钥。但事情比这更糟糕。假设不是fprintf_s获取用户定义的格式字符串,而是获取snprintf_s. 然后,通过提供精心设计的格式字符串,就可以破坏进程的某些部分,从而将代码注入其中。考虑一下这种情况发生在处理来自互联网的数据的工具中:这就是安全漏洞的发生方式。