You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 16 Next »

It is highly unlikely that a method is built to deal with all possible runtime exceptions; therefore no method should ever catch RuntimeException. If a method catches RuntimeException, it will receive exceptions it was not designed to handle, such as NullPointerException. Many catch clauses simply log or ignore their error, and resume control flow. But runtime exceptions represent a bug in the program that should be fixed by the developer, and almost always lead to control flow vulnerabilities.

Likewise, a method should never catch Exception or Throwable, since this implies catching RuntimeException.

Noncompliant Code Example

The following function takes a string and returns true if it consists of a capital letter succeeded by lowercase letters. To handle corner cases, it merely wraps the code in a try/catch block and reports any exceptions that arise.

boolean isCapitalized(String s) {
  try {
    if (s.equals("")) {
      return true;
    }
    String first = s.substring( 0, 1);
    String rest = s.substring( 1);
    return (first.equals( first.toUpperCase()) &&
	    rest.equals( rest.toLowerCase()));
  } catch (RuntimeException exception) {
    ExceptionReporter.report(exception);
  }
  return false;
}

This code will report errors such as if s is a null pointer, or is the empty string. However, it will also catch other errors unlikely to be handled properly, such as if the string belongs to a different thread.

Compliant Solution

Intead of catching RuntimeException, a program should catch very specific exceptions.

boolean isCapitalized(String s) {
  try {
    if (s.equals("")) {
      return true;
    }
    String first = s.substring( 0, 1);
    String rest = s.substring( 1);
    return (first.equals( first.toUpperCase()) &&
	    rest.equals( rest.toLowerCase()));
  } catch (NullPointerException exception) {
    ExceptionReporter.report( exception);
  }
  return false;
}

This code will only catch exceptions intended by the programmer to be caught. A concurrency-based exception will not be caught by this code, and can therefore be managed by code more specifically designed to handle it.

Noncompliant Code Example

In this noncompliant code example, a divide by zero exception was handled initially. Instead of the specific exception type ArithmeticException, a more generic type Exception was caught. This is dangerous since any future exception updates to the method signature (such as, addition of IOException here) may no longer require the developer to provide a handler. Consequently, the recovery process may not be tailored to the specific exception type that gets thrown. Additionally, unchecked exceptions under RuntimeException are also unintentionally caught when the top level Exception class is caught.

public class DivideException {
  public static void main(String[] args) {
    try {
      division(200,5);
      division(200,0); //divide by zero        
    } catch (Exception e) { System.out.println("Divide by zero exception : " + e.getMessage()); }    	                    
  }

  public static void division(int totalSum, int totalNumber) throws ArithmeticException, IOException  {  
    int average  = totalSum/totalNumber; 
    System.out.println("Average: "+ average);   	
  }
}

Noncompliant Code Example

This noncompliant example improves by catching a specific divide-by-zero exception but fails on the premise that it unscrupulously accepts other undesirable runtime exceptions, by catching Exception.

try {
  division(200,5);
  division(200,0); //divide by zero        
} catch (ArithmeticException ae) { throw new DivideByZeroException(); }
  // DivideByZeroException extends Exception so is checked
  catch (Exception e) { System.out.println("Exception occurred :" + e.getMessage()); }	

Compliant Solution

To be compliant, catching specific exception types is advisable especially when the types differ significantly. Here, Arithmetic Exception and IOException have been unbundled as they belong to very diverse categories.

import java.io.IOException;

public class DivideException {
  public static void main(String[] args) {
    try {
      division(200,5);
      division(200,0); //divide by zero        
    } catch (ArithmeticException ae) { throw new DivideByZeroException(); }
      // DivideByZeroException extends Exception so is checked
      catch (IOException ie) { System.out.println("I/O Exception occurred :" + ie.getMessage()); }	    
  }

  public static void division(int totalSum, int totalNumber) throws ArithmeticException, IOException  {  
    int average  = totalSum/totalNumber; 
    System.out.println("Average: "+ average);   	
  }
}

Exceptions

EXC32-J-EX1: A secure application must also abide by [EXC01-J. Do not allow exceptions to transmit sensitive information]. In order to follow this rule, an application might find it necessary to catch all exceptions at some 'top' level in order to sanitize (or suppress) them. This is also summarized in the CWE entries, CWE 7 and CWE 388. If exceptions need to be caught, it is better to catch Throwable instead of Exception [[Roubtsov 03]].

Risk Assessment

Catching RuntimeException will trap several types of exceptions not intended to be caught. This prevents them from being handled properly.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

EXC32-J

low

likely

medium

P6

L2

Automated Detection

TODO

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

[[MITRE 09]] CWE ID 396 "Declaration of Catch for Generic Exception", CWE ID 7 "J2EE Misconfiguration: Missing Error Handling", CWE ID 537 "Information Leak Through Java Runtime Error Message", CWE ID 536 "Information Leak Through Servlet Runtime Error Message"
[[Schweisguth 03]]
[[JLS 05]] Chapter 11, Exceptions
[[Tutorials 08]] Exceptions
[[Doshi 03]]
[[Muller 02]]


EXC03-J. Try to recover gracefully from system errors      10. Exceptional Behavior (EXC)      EXC30-J. Do not exit abruptly from a finally block

  • No labels