Java String.format() 是否可以防止字符串注入?

Does Java String.format() prevent String injection?

我一直在准备技术面试。所以在一件事上我只是不确定。例如,如果我写

try {
...
} catch (InterruptedException ie) {
    throw new IllegalStateException(String.format("Player [%s]: failed to reply message [%s]"), ie);
}

这是否已经阻止了字符串注入?还是我必须像下面这样写:

String errorMsg = String.format("Player [%s]: failed to reply message [%s]");
throw new IllegalStateException(errorMsg, ie);

两个片段之间没有区别。两者都不能防止 'string injection'.

只有 4 non-boneheaded 种针对字符串注入攻击的缓解措施:

  1. 确保where-ever字符串结束,这不可能是任何方式或形式的安全问题。例如,如果您的数据是一个二进制文件,所有系统操作员都知道该文件的内容直接来自网络,那么上传的内容无关紧要。

  2. 根本不渲染字符串。把孩子和洗澡水一起倒掉。

  3. 使用白名单。如果字符串仅包含这些允许的内容,则允许它。默认不允许。

  4. 使用转义器。

  5. 黑名单概念荣誉奖:列出 known-malicious 内容,并允许所有字符串,除非它们包含黑名单中的内容。 这是愚蠢的,永远不应该使用。例如,如果您扫描 <script> 的传入数据,您就搞砸了。不要这样做。它不起作用。黑名单被轻而易举地绕过了。白名单就是您要找的。

最常见的策略是第 4 种:逃避者。例如,当您有一个网络服务器接收用户名和用户的电话 phone 号码以及用户的全名,然后将所有这些信息呈现在他们的 public 网站上时,那么:

  • phone 号应该使用白名单策略来缓解。单个 +、0-9 范围内的数字、空格、破折号,仅此而已。如果那是输入的样子,请允许它。否则不要。

  • 用户的真实姓名应该通过转义来减轻:获取提供的数据并将其逐字注入您的数据库,但在与该数据的所有交互中都将此数据视为已污染:例如,当呈现 public 页面时,'full name' 字符串需要通过 HTML 转义符进行清洗,例如将所有 < 替换为 &lt;.

您的代码不做这 4 件事中的任何一件(它的任何一个版本)。

一般来说,将异常的 .getMessage() 返回的字符串视为已经 'safe'(转义/通过白名单验证程序)是一个非常糟糕的主意。相反,调用 .getMessage() 的代码需要应用上述 4 种缓解措施之一。