使用外部控制的格式字符串¶
ID: java/tainted-format-string
Kind: path-problem
Security severity: 9.3
Severity: error
Precision: high
Tags:
- security
- external/cwe/cwe-134
Query suites:
- java-code-scanning.qls
- java-security-extended.qls
- java-security-and-quality.qls
String.format
方法和相关方法,如 PrintStream.printf
和 Formatter.format
,都接受一个格式字符串,该字符串用于通过提供内联格式说明符来格式化格式调用后的尾随参数。如果格式字符串包含来自不受信任来源的未经消毒的输入,那么该字符串可能包含额外的格式说明符,导致抛出异常或泄露信息。
格式方法的 Java 标准库实现如果格式说明符与参数类型不匹配,或者参数过少或过多,都会抛出异常。如果在格式字符串中使用未经消毒的输入,它可能包含无效的额外格式说明符,从而导致抛出异常。
位置格式说明符可用于通过位置访问格式调用的参数。格式字符串中的未经消毒的输入可以使用位置格式说明符来访问不应可见的信息。例如,在格式化 Calendar 实例时,我们可能只打算打印年份,但用户指定的格式字符串可能包含一个说明符来访问月份和日期。
建议¶
如果作为格式字符串传递的参数意图是普通字符串而不是格式字符串,那么将 %s
作为格式字符串传递,并将原始参数作为唯一的尾随参数传递。
示例¶
以下程序旨在检查存储的信用卡的安全码
public class ResponseSplitting extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Calendar expirationDate = new GregorianCalendar(2017, GregorianCalendar.SEPTEMBER, 1);
// User provided value
String cardSecurityCode = request.getParameter("cardSecurityCode");
if (notValid(cardSecurityCode)) {
/*
* BAD: user provided value is included in the format string.
* A malicious user could provide an extra format specifier, which causes an
* exception to be thrown. Or they could provide a %1$tm or %1$te format specifier to
* access the month or day of the expiration date.
*/
System.out.format(cardSecurityCode +
" is not the right value. Hint: the card expires in %1$ty.",
expirationDate);
// GOOD: %s is used to include the user-provided cardSecurityCode in the output
System.out.format("%s is not the right value. Hint: the card expires in %2$ty.",
cardSecurityCode,
expirationDate);
}
}
}
然而,在第一个格式调用中,它使用用户提供的 cardSecurityCode 在格式字符串中。如果用户在 cardSecurityCode 字段中包含格式说明符,他们可能会导致异常抛出,或者能够访问有关存储的卡过期日期的额外信息。
第二个格式调用展示了正确的方法。用户提供的 value 作为参数传递给格式调用。这阻止了用户提供的 value 中的任何格式说明符被评估。
参考文献¶
SEI CERT Oracle Java 编码标准:IDS06-J. 从格式字符串中排除未经消毒的用户输入.
Java 教程:格式化数字打印输出.
Java API 规范:Formatter.
常见漏洞枚举:CWE-134.