`std::format` 容易受到格式字符串攻击吗?如何缓解?

Is `std::format` vulnerable to format string attack? How to mitigate it?

我想将使用 printffprintf 等的 C 风格代码重构为 C++。 std::format 是否像前面提到的 C 函数一样容易受到格式字符串攻击?

如果我搜索格式字符串攻击,我只找到 stdio format string vulnerabilities。我想知道更多关于 std::format 是否易受攻击,以及如何缓解它,即使我必须格式化用户提供的字符串。

std::format,与 printf/etc. 一样,假定格式字符串来自受信任的来源。 std::format 的恶意格式字符串通常不会引起与 printf/etc 相同的特定问题。 (隐式类型双关语、缓冲区溢出等),尽管 std::format 有一些自定义支持可能会导致此类问题(和其他问题)。

如果你想使用std::format,那么你需要确保格式字符串是正确的,要么自己写,要么验证它是否具有你期望的特定形式。

I would like to know more about if std::format is vulnerable, and how to mitigate it, even if I have to format user provided strings.

即使您使用 std::vformat(接受 运行 时间字符串),输入也会根据其他参数的类型进行验证,并且 std::format_error 在不匹配时引发(而 std::format 在编译期间在调用站点验证这一点)。

因此,恶意用户无法为您未提供的参数偷偷使用格式说明符。由于用于参数的格式化程序必须基于其静态类型(因此也由您提供),攻击者无法尝试双关。

总而言之,那个攻击方向似乎被阻止了。

printf 这样的 C 函数使用 variadic arguments,它不提供任何方法来检测实际传递的参数的类型和数量。 printf 可以判断的唯一方法是检查格式字符串。如果这个字符串是谎言,那么你就有了 UB。

另一方面,std::format 是一个模板函数,其中参数的所有类型和数量在编译时都是已知的。它确实知道每种类型是什么,而且,它会在编译时检查字符串是否与类型匹配。与 std::vformat 相同,它以相同的方式知道类型(使用其 std::format_args 参数中的信息),并检查字符串的有效性,尽管是在运行时。

因此,这种类型的攻击,即使用恶意字符串,被拒绝了。