Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: changed naming of wrapped functions and indentation

...

Code Block
bgColor#FFcccc
public void fio52processFile_nce1nce(String filename){
	  // Identify a file by its path
    Path file1 = Paths.get(filename);
 
 
    // Open the file for writing
    try(BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(file1)))) {
        // Write to file...
    } catch (Exception e) {
    	System.out.println("Exception during file access" + e);
    } 
  
   // Close the file
   
  /*
     * A race condition here allows for an attacker to switch
     * out the file for another
     */

    // Reopen the file for reading
    Path file2 = Paths.get(filename);
    
    
    try(BufferedReader br = new BufferedReader(new InputStreamReader(Files.newInputStream(file2)))){
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
    } catch (Exception e) {
        System.out.println("Exception during file access" + e);
    }
}

There is no guarantee that the file opened for reading is the same file that was opened for writing. An attacker can replace the original file (for example, with a symbolic link) between the first call to close() and the subsequent creation of the BufferedReader.

...

Code Block
bgColor#FFcccc
public void fio52sameFile_nce2nce(String filename){
    // Identify a file by its path
    Path file1 = Paths.get(filename);
  
   // Open the file for writing
    try(BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(file1)))) {
            // Write to file
    } catch (Exception e) {
      System.out.println("Exception during file access" + e);
    } 
  
   // ...
    // Reopen the file for reading
    Path file2 = Paths.get(filename);
    if (!Files.isSameFile(file1, file2)) {
      System.out.println("File tampered with");
      // Handle error
    }
  
   try(BufferedReader br = new BufferedReader(new InputStreamReader(Files.newInputStream(file2)))) { 
            String line;
            while ((line = br.readLine()) != null) {
                    System.out.println(line);
            }
    } catch (Exception e) {
      System.out.println("Exception during file access" + e);
    }
}

Unfortunately, there is no guarantee that the method isSameFile() really checks that the files are the same file. The Java 7 API for isSameFile() says:

...

Code Block
bgColor#ccccff
public void fio52sameFile_cs1cs(String filename) throws IOException{
   // Identify a file by its path
   Path file1 = Paths.get(filename);
   BasicFileAttributes attr1 = Files.readAttributes(file1, BasicFileAttributes.class);
   FileTime creation1 = attr1.creationTime();
   FileTime modified1 = attr1.lastModifiedTime();

   // Open the file for writing
   try(BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(file1)))) {
           // Write to file...
   } catch (Exception e){
           System.out.println("Exception during file access" + e);
   } 
  
  // Reopen the file for reading
   Path file2 = Paths.get(filename);
   BasicFileAttributes attr2 = Files.readAttributes(file2, BasicFileAttributes.class);
   FileTime creation2 = attr2.creationTime();
   FileTime modified2 = attr2.lastModifiedTime();
   if ( (!creation1.equals(creation2)) || (!modified1.equals(modified2)) ) {
     System.out.println("File tampered with");
     // Handle error
   }
  
  try(BufferedReader br = new BufferedReader( new InputStreamReader(Files.newInputStream(file2)))){
		    String line;
        while ((line = br.readLine()) != null) {
        	System.out.println(line);
        }
   } catch (Exception e){
       System.out.println("Exception during file access" + e);
   }
}

Although this solution is reasonably secure, a determined attacker could create a symbolic link with the same creation and last-modified times as the original file. Also, a time-of-check, time-of-use (TOCTOU) race condition occurs between the time the file's attributes are first read and the time the file is first opened. Likewise, a second TOCTOU condition occurs the second time the attributes are read and the file is reopened.

...

Code Block
bgColor#ccccff
public void fio52filekey_cs2cs(String filename) throws IOException{
    // Identify a file by its path
    Path file1 = Paths.get(filename);
    BasicFileAttributes attr1 = Files.readAttributes(file1, BasicFileAttributes.class);
    Object key1 = attr1.fileKey();
    // Open the file for writing
    try(BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(file1)))) {
            // Write to file
    } catch (Exception e) {
      	System.out.println("Exception during file access" + e);
    } 
  
   // Reopen the file for reading
    Path file2 = Paths.get(filename);
    BasicFileAttributes attr2 = Files.readAttributes(file2, BasicFileAttributes.class);
    Object key2 = attr2.fileKey();

    if ( !key1.equals(key2) ) {
      System.out.println("File tampered with");
      // Handle error
    }

    try(BufferedReader br = new BufferedReader(new InputStreamReader(Files.newInputStream(file2)))) {
    	String line;
        while ((line = br.readLine()) != null) {
        	System.out.println(line);
        }
    } catch (Exception e) {
        System.out.println("Exception during file access" + e);
    }
} 

This approach will not work on all platforms. For example, on an Intel Core i5-2400 machine running Windows 7 Enterprise, all fileKey attributes are null.

...

Code Block
bgColor#ccccff
public void fio52randomAccess_cs3cs(String filename) throws IOException{
    // Identify a file by its path
    RandomAccessFile file = new RandomAccessFile( filename, "rw");

    // Write to file...

    // Go back to beginning and read contents
    file.seek(0);
    try {
      while (true) {
        String s = file.readUTF();
        System.out.print(s);
      }
    } catch (EOFException x) {
      // Ignore, this breaks out of while loop
    }
    br.close();
}

Noncompliant Code Example (file size)

...

Code Block
bgColor#ffcccc
langjava
static long goodSize = 1024;

public void doSomethingWithFile(String filename) {
  long size = new File( filename).length();
  if (size != goodSize) {
    System.out.println("File is wrong size!");
    return;
  }

  try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream( filename)))) {
      // ... work with file
    } catch (Exception e) {
      System.out.println("Exception during file access" + e);
  }
}

...

Code Block
bgColor#ccccff
langjava
static long goodSize = 1024;

public void doSomethingWithFile(String filename) {
  try (FileInputStream in = new FileInputStream( filename);
     BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
      long size = in.getChannel().size();
      if (size != goodSize) {
        System.out.println("File is wrong size!");
        return;
      }

      String line;
      while ((line = br.readLine()) != null) {
        System.out.println(line);
      }
    } catch (Exception e) {
      System.out.println("Exception during file access" + e);
  }
}

...