在 Python 3 中使用用户输入进行字符串格式化的安全方法和做法有哪些?

Which are safe methods and practices for string formatting with user input in Python 3?

我的理解

从各种渠道,我了解到Python 3(3.6+ for f-strings)中的字符串formatting/interpolation有四种主要技术:

  1. %格式化,类似于C的printf
  2. str.format()方法
  3. 格式化字符串literals/f-strings
  4. 来自标准库string模块的模板字符串

我的用法知识主要来自Python String Formatting Best Practices (source A):

我知道 str.format() 中的上述漏洞来自可用于任何普通字符串的方法,其中定界大括号是字符串数据本身的一部分。可以将包含大括号分隔的替换字段的恶意用​​户输入提供给访问环境属性的方法。我相信这与其他格式化方式不同,在其他格式化方式中,程序员是唯一可以为预格式化字符串提供变量的人。例如,f-strings have similar syntax to str.format() but, because f-strings are literals and the inserted values are evaluated separately through concatenation-like behavior, they are not vulnerable to the same attack (source B)。 %-formatting 和 Template strings 似乎也只是提供给程序员替换的变量;指出的主要区别是模板的功能更有限。

我的困惑

我看到很多人都在强调 str.format() 的漏洞,这让我想知道在使用其他技术时应该注意什么。 来源 A 将模板字符串描述为上述方法中最安全的方法,“因为它们降低了复杂性”:

The more complex formatting mini-languages of the other string formatting techniques might introduce security vulnerabilities to your programs.

  1. 是的,似乎 f-strings 不像 str.format() 那样容易受到攻击,但是是否存在隐含的 f-string 安全性的已知问题通过 来源 A?问题是否更像是未知漏洞利用和意外交互的风险缓解?

我不熟悉 C,也不打算使用更笨重的 %/printf 格式,但我听说 C 的 printf 有自己的格式潜在的漏洞。此外,来源 A 和来源 B 似乎暗示此方法缺乏安全性。 Source B 中的最佳答案是,

String formatting may be dangerous when a format string depends on untrusted data. So, when using str.format() or %-formatting, it's important to use static format strings, or to sanitize untrusted parts before applying the formatter function.

  1. % 风格的字符串是否存在已知的安全问题?
  2. 最后,应该使用哪些方法以及如何防止基于用户输入的攻击(例如使用正则表达式过滤输入)?
    • 更具体地说,模板字符串真的是更安全的选择吗?在授予更多功能的同时,能否同样轻松、安全地使用 f 弦?

无论您选择哪种格式,任何格式和库都有其自身的缺点和漏洞。您需要问自己的更大问题是您面临的风险因素和情景是什么,以及您将如何应对。 首先问问自己:是否会出现用户或某种外部实体(例如外部系统)向您发送格式字符串的情况?如果答案是否定的,则没有风险。如果答案是肯定的,您需要查看是否需要这样做。如果不是 - 删除它以消除风险。 如果需要 - 您可以执行基于白名单的输入验证,并从允许字符列表中排除所有格式特定的特殊字符,以消除风险。例如,没有格式字符串可以传递 ^[a-zA-Z0-9\s]*$ 通用正则表达式。

所以底线是:使用哪种格式字符串类型并不重要,真正重要的是你用它做什么以及如何减少和消除它被篡改的风险。