Skip to end of metadata
Go to start of metadata

Although creating a file is usually accomplished with a single method call, this single action raises multiple security-related questions. What should be done if the file cannot be created? What should be done if the file already exists? What should be the file's initial attributes, such as permissions?

Java provides several generations of file-handling facilities. The original input/output facilities, which included basic file handling, are in the package java.io. More comprehensive facilities were included in JDK 1.4 with the New I/O package java.nio (see New I/O APIs [Oracle 2010b]). Still more comprehensive facilities were included in JDK 1.7 with the New I/O 2 package java.nio.file. Both packages introduced a number of methods to support finer-grained control over file creation.

FIO01-J. Create files with appropriate access permissions explains how to specify the permissions of a newly created file.

Noncompliant Code Example

This noncompliant code example tries to open a file for writing:

public void createFile(String filename) 
    throws FileNotFoundException{
  OutputStream out = new FileOutputStream(filename);
  // Work with file
}

If the file existed before being opened, its former contents will be overwritten with the contents provided by the program.

Noncompliant Code Example (TOCTOU)

This noncompliant code example tries to avoid altering an existing file by creating an empty file using java.io.File.createNewfile(). If a file with the given name already exists, then createNewFile() will return false without destroying the named file's contents.

public void createFile(String filename)
    throws IOException{
  OutputStream out = new FileOutputStream(filename, true);
  if (!new File(filename).createNewFile()) {
      // File cannot be created...handle error
  } else {
      out = new FileOutputStream(filename);
      // Work with file
  }
} 

Unfortunately, this solution is subject to a TOCTOU (time-of-check, time-of-use) race condition. It is possible for an attacker to modify the file system after the empty file is created but before the file is opened, such that the file that is opened is distince from the file that was created.

Compliant Solution (Files)

This compliant solution uses the java.nio.file.Files.newOutputStream() method to atomically create the file and throws an exception if the file already exists:

public void createFile(String filename) 
    throws FileNotFoundException{
  try (OutputStream out = new BufferedOutputStream(
         Files.newOutputStream(Paths.get(filename),
                               StandardOpenOption.CREATE_NEW))) {
    // Work with out
  } catch (IOException x) {
      // File not writable...handle error
  }
} 

Applicability

The ability to determine whether an existing file has been opened or a new file has been created provides greater assurance that only the intended file is opened or overwritten and that other files remain undisturbed.

Bibliography

 


5 Comments

  1. Note that the introduction to the rule raises multiple questions, most of which remain unaddressed by this rule. Perhaps the rule's intro could be used to introduce a group of rules that collectively address those issues.

    1. Actually the examples answer those questions, except for how to handle file permissions, which is handled by FIO01-J. Amended the intro to include this.

  2. The append example doesn't add anything in my opinion, and we have to compliant solution to go with it.  I'm going to delete it shortly unless someone has some good argument to keep it.

    Noncompliant Code Example (Append)

    This noncompliant code example tries to avoid overwriting an existing file:

    public void noOverwrite_nce(String filename) throws FileNotFoundException{
      OutputStream out = new FileOutputStream(filename, true);
      // Work with FILE
    }

    If the file existed before being opened, any new data written out will be appended to the former contents. This code is compliant only if this behavior matches the intent of the programmer.

     

  3. Method names should be identical in NCE and CS.