Java input classes such as Scanner
and BufferedInputStream
facilitate fast, nonblocking I/O by buffering an underlying input stream. Programs can create multiple wrappers on an InputStream
. Programs that use multiple wrappers around a single input stream, however, can behave unpredictably depending on whether the wrappers allow look-ahead. An attacker can exploit this difference in behavior by, for example, by redirecting System.in
(from a file) or by using the System.setIn()
method to redirect System.in
. In general, any input stream that supports nonblocking buffered I/O is susceptible to this form of misuse.
...
Likewise, an output stream must not have more than one buffered wrapper , as because multiple wrappers can cause multiple output strings to be output in an unexpected order. For example, the javax.servlet.ServletResponse
allows for the creation of a PrintWriter
or an OutputStream
to hold the response generated by a web servlet. But only one or the other should be used, not both.
...
Code Block | ||
---|---|---|
| ||
public final class InputLibrary { public static char getChar() throws EOFException, IOException { BufferedInputStream in = new BufferedInputStream(System.in); // wrapperWrapper int input = in.read(); if (input == -1) { throw new EOFException(); } // Down casting is permitted because InputStream guarantees read() in range // 0..255 if it is not -1 return (char) input; } public static void main(String[] args) { try { // Either redirect input from the console or use // System.setIn(new FileInputStream("input.dat")); System.out.print("Enter first initial: "); char first = getChar(); System.out.println("Your first initial is " + first); System.out.print("Enter last initial: "); char last = getChar(); System.out.println("Your last initial is " + last); } catch (EOFException e) { System.err.println("ERROR"); // Forward to handler } catch (IOException e) { System.err.println("ERROR"); // Forward to handler } } } |
...
Create and use only a single BufferedInputStream
on System.in
. This compliant solution ensures that all methods can access the BufferedInputStream
by declaring it as a class variable.:
Code Block | ||
---|---|---|
| ||
public final class InputLibrary { private static BufferedInputStream in = new BufferedInputStream(System.in); public static char getChar() throws EOFException, IOException { int input = in.read(); if (input == -1) { throw new EOFException(); } in.skip(1); // This statement is to advance to the next line. // The noncompliant code example deceptively // appeared to work without it (in some cases). return (char) input; } public static void main(String[] args) { try { System.out.print("Enter first initial: "); char first = getChar(); System.out.println("Your first initial is " + first); System.out.print("Enter last initial: "); char last = getChar(); System.out.println("Your last initial is " + last); } catch (EOFException e) { System.err.println("ERROR"); // Forward to handler } catch (IOException e) { System.err.println("ERROR"); // Forward to handler } } } |
...
This compliant solution uses both System.in
and the InputLibrary
class, which creates a buffered wrapper around System.in
. Because the InputLibrary
class and the remainder of the program must share a single buffered wrapper, the InputLibrary
class must export a reference to that wrapper. Code outside the InputLibrary
class must use the exported wrapper rather than creating create and using use its own additional buffered wrapper around System.in
.
Code Block | ||
---|---|---|
| ||
public final class InputLibrary { private static BufferedInputStream in = new BufferedInputStream(System.in); static BufferedInputStream getBufferedWrapper() { return in; } // ...other Other methods } // Some code that requires user input from System.in class AppCode { private static BufferedInputStream in; AppCode() { in = InputLibrary.getBufferedWrapper(); } // ...other Other methods } |
Note that reading from a stream is not a thread-safe operation by default; consequently, this compliant solution may be inappropriate in multithreaded environments. In such cases, explicit synchronization is required.
Risk Assessment
...
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
FIO06-J | lowLow | unlikelyUnlikely | mediumMedium | P2 | L3 |
Automated Detection
Sound automated detection of this vulnerability is not feasible in the general case. Heuristic approaches may be useful.
Bibliography
[API 2006] | ||||
[API | 20062014] | Class BufferedInputStream |
| Class ServletOutputStream |
[Fortify 2014] | Multiple Stream Commits |
...