Java 使用用户输入的字符串作为格式控件意味着什么?为什么会违反安全性?

Java 使用用户输入的字符串作为格式控件意味着什么?为什么会违反安全性?,java,Java,我在Deitel和Deitel的书《Java:如何编程》中读到了这个错误预防技巧(3.1)。我不明白这是什么意思。我只知道它在谈论下面的代码行: // display the name stored in object myAccount System.out.printf("Name in object myAccount is:%n%s%n", myAccount.getName()); 该段内容如下: 切勿将用户输入的字符串用作格式控件。当方法System.out.printf在其第一个

我在Deitel和Deitel的书《Java:如何编程》中读到了这个错误预防技巧(3.1)。我不明白这是什么意思。我只知道它在谈论下面的代码行:

// display the name stored in object myAccount
System.out.printf("Name in object myAccount is:%n%s%n", myAccount.getName());
该段内容如下:

切勿将用户输入的字符串用作格式控件。当方法
System.out.printf
在其第一个参数中计算格式控制字符串时,该方法将根据该字符串中的转换说明符执行任务。如果从用户处获得格式控制字符串,恶意用户可能会提供转换说明符,这些说明符将由
System.out.printf
执行,可能会导致安全漏洞


严格地说,使用用户输入的字符串进行格式控制如下:

String format=getFromUser(...);
System.out.printf(format, arg1, arg2, arg3...);
这可能是非常有害的,因为除了@JohnKugelman建议的编码注入之外,我可以想出四种简单的方法,恶意用户可以通过以下方式破坏安全:

  • 最简单的方法是输入错误的掩码,以便在运行时抛出
    ErrorFormatConversion
  • 通过输入较高的字段宽度,以便输出如此大的行,因此无法读取:
然后,想象你自己是一个试图破坏这个程序的黑客。使用以下建议值执行:

  • %)/$#
  • %1000$d
  • %10000000000d
  • %01000000d

结论:格式字符串必须由程序员而不是最终的交互用户组成。

恶意用户可能会在我的脑海中插入一个格式说明符,该说明符可确定在控制台上显示的代码中某个字符串的长度(读取:字符数)。然后,您可能泄漏了用户从未打算看到的信息。这在C语言中是一个非常大的问题,恶意格式字符串可用于打印堆栈中的任意数据,甚至可以使用
%n
说明符将内容写入内存。我尝试输入一个包含说明符(如%s或%n)的输入,但它们的打印方式相同,不能作为说明符读取,因此,我不知道这怎么会导致任何问题,因为如果我没有弄错的话,编译器会计算第一个参数并将第二个参数粘贴到用户输入中-其中%s在第一个参数中。我认为引号不适用于该行代码。那
printf
很好。坏的
printf
是在第一个参数中有一个用户输入变量的函数,比如
System.out.printf(“我的名字是“+myAccount.getName()+%n”)
。谢谢@LittleSanti,但我仍然不明白你的意思。因此,针对您提到的第一类错误,我在计算机上尝试了该代码,但失败了,因为%符号后面没有格式说明符,在本例中为“s”。这与其他事情无关。简单语法错误。我想我从这句话中了解到的是字符串a1=“s”;字符串a2=“一月”;系统输出打印F(“%s”,a1,a2);为了进一步解释我的困惑,在你提到的第一种类型中,唯一的错误来源是程序员。如果我从用户处获取输入“一月”,则(据我所知)用户无法输入任何内容而不是“一月”,这将导致问题或被视为(n)攻击/破坏。因此,由于printf的第一个参数是在用户输入被替换并打印之前处理的,所以输出总是用户输入的内容。无法进行任何操作,因为已完成格式说明符的处理。是吗?是的,你是对的,@Max。我看我的解释不太清楚。查看我的更新。 @Test public void wrongMask() { String s="january"; System.out.printf("%)/$#", s); } @Test public void highArgumentIndex() { String s="january"; System.out.printf("%1000$s%n", s); } @Test public void highFieldWidth() { String s="january"; System.out.printf("%1000000s%n", s); } @Test public void highArgumentWidth() { int n=12; System.out.printf("%01000000d%n", n); } public static void main(String[] args) { String format=args[0]; int n=12; System.out.printf(format, n); }