Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: assimilated MET21-J

...

Code Block
bgColor#ccccff
class XCard {
  private String type;
  private Card card; // Composition
  
  public XCard(int number, String type) {
    card = new Card(number);
    this.type = type;
  }
	  
  public Card viewCard() {
    return card;
  }

  public boolean equals(Object o) {
    if (!(o instanceof XCard)) {
      return false;
    }
      
    XCard cp = (XCard)o;
    return cp.card.equals(card) && cp.type.equals(type);
  }
	  
  public static void main(String[] args) {
    XCard p1 = new XCard(1, "type1");
    Card p2 = new Card(1);
    XCard p3 = new XCard(1, "type2");
    XCard p4 = new XCard(1, "type1");
    System.out.println(p1.equals(p2)); // Prints false
    System.out.println(p2.equals(p3)); // Prints false
    System.out.println(p1.equals(p3)); // Prints false
    System.out.println(p1.equals(p4)); // Prints true
  }
}

...

Noncompliant Code Example (Consistency)

Wiki Markup
*MET12-EX0:* This guideline may be violated provided that the incompatible types are never compared.  There are classes in the Java platform libraries (and elsewhere) that extend an instantiable class by adding a value component.  For example, {{java.sql.Timestamp}} extends {{java.util.Date}} and adds a nanoseconds field. The {{equals}} implementation for {{Timestamp}} violates symmetry and can cause erratic behavior if {{Timestamp}} and {{Date}} objects are used in the same collection or are otherwise intermixed. \[[Bloch 2008|AA. Bibliography#Bloch 08]\]

Risk Assessment

Violating the general contract when overriding the equals() method can lead to unexpected results.

Guideline

Severity

Likelihood

Remediation Cost

Priority

Level

MET12-J

low

unlikely

medium

P2

L3

Related Vulnerabilities

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

Bibliography

A Uniform Resource Locator (URL) specifies both the location of a resource and also a method to access it.  According to Java API \[SD:[API 2006|AA. Bibliography#API 06]\] regarding the {{equals()}} method for {{java.net.URL}} objects:

Two URL objects are equal if they have the same protocol, reference equivalent hosts, have the same port number on the host, and the same file and fragment of the file.
Two hosts are considered equivalent if both host names can be resolved into the same IP addresses; else if either host name can't be resolved, the host names must be equal without regard to case; or both host names equal to null.
Note: The defined behavior for equals is known to be inconsistent with virtual hosting in HTTP.

The concept of virtual hosting allows a web server to host multiple websites on the same computer, sometimes sharing the same IP address. Unfortunately, this technique was unanticipated when the URL class was designed. Consequently, when two completely different URLs resolve to the same IP address, the URL class considers them to be equal.

Another risk associated with the equals() method for URL objects is that the logic it uses when connected to the Internet differs from that used when disconnected. When connected to the Internet, the equals() method follows the steps described in the Java API; when disconnected, it performs a string compare on the two URLs. Consquently, the URL.equals() method violates the consistency requirement for equals().

Consider an application that allows an organization's employees to access an external mail service via http://mailwebsite.comImage Added. The application is designed to deny access to other websites by behaving as a makeshift firewall. However, a crafty or malicious user can nevertheless access an illegal website http://illegalwebsite.comImage Added that is hosted on the same computer as the legitimate website and consequently shares the same IP address. Even worse, an attacker can register multiple websites (for phishing purposes) until one is registered on the same computer, consequently defeating the firewall.

Code Block
bgColor#FFCCCC

public class Filter {
  public static void main(String[] args) throws MalformedURLException {
    final URL allowed = new URL("http://mailwebsite.com");
    if (!allowed.equals(new URL(args[0]))) {
      throw new SecurityException("Access Denied");
    } 
    // Else proceed 
  }
}

Compliant Solution (strings)

This compliant solution compares two URL's string representations, thereby avoiding the pitfalls of URL.equals().

Code Block
bgColor#ccccff

public class Filter {
  public static void main(String[] args) throws MalformedURLException {
    final URL allowed = new URL("http://mailwebsite.com");
    if (!allowed.toString().equals(new URL(args[0]).toString())) {
      throw new SecurityException("Access Denied");
    } 
    // Else proceed 
  }
}

This solution still has problems. Two URLs with different string representation can still easily point to the same resource. However, the solution works well in this case because the equals() contract is preserved, and the system will never allow a malicious URL to be accepted by mistake.

Compliant Solution (URI.equals())

Wiki Markup
A Uniform Resource Identifier (URI) contains a string of characters used to identify a resource; this is a more general concept than a URL. The {{java.net.URI}} class provides string-based {{equals()}} and {{hashCode()}} methods that satisfy the general contracts for {{Object.equals()}} and {{Object.hashCode()}}; they do not invoke hostname resolution and are unaffected by network connectivity.  {{URI}} also provides methods for normalization and canonicalization that {{URL}} lacks. Finally, the {{URL.toURI()}} and {{URI.toURL()}} methods provide easy conversion between the two classes. It is recommended to use URIs instead of URLs whenever possible. According to the Java API \[[API 2006|AA. Bibliography#API 06]\], {{URI}} class documentation

A URI may be either absolute or relative. A URI string is parsed according to the generic syntax without regard to the scheme, if any, that it specifies. No lookup of the host, if any, is performed, and no scheme-dependent stream handler is constructed.

This compliant solution uses a URI object instead of a URL. The filter appropriately blocks the website when present with a string different from http://mailwebsite.comImage Added, because the comparison fails.

Code Block
bgColor#ccccff

public class Filter {
  public static void main(String[] args) throws MalformedURLException, URISyntaxException {
    final URI allowed = new URI("http://mailwebsite.com");
    if (!allowed.equals(new URI(args[0]))) {
      throw new SecurityException("Access Denied");
    }
    // Else proceed
  }
}

Wiki Markup
Additionally, the {{URI}} class also performs normalization (removing extraneous path segments like '..') and relativization of paths \[[API 2006|AA. Bibliography#API 06]\] and \[[Darwin 2004|AA. Bibliography#Darwin 04]\]. 

Exceptions

Wiki Markup
*MET12-EX0:* This guideline may be violated provided that the incompatible types are never compared.  There are classes in the Java platform libraries (and elsewhere) that extend an instantiable class by adding a value component.  For example, {{java.sql.Timestamp}} extends {{java.util.Date}} and adds a nanoseconds field. The {{equals}} implementation for {{Timestamp}} violates symmetry and can cause erratic behavior if {{Timestamp}} and {{Date}} objects are used in the same collection or are otherwise intermixed. \[[Bloch 2008|AA. Bibliography#Bloch 08]\]

Risk Assessment

Violating the general contract when overriding the equals() method can lead to unexpected results.

Guideline

Severity

Likelihood

Remediation Cost

Priority

Level

MET12-J

low

unlikely

medium

P2

L3

Related Vulnerabilities

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

Bibliography

Wiki Markup
\[[API 2006|AA. Bibliography#API 06]\] [method equals()|http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#equals(java.lang.Object)]
\[[Bloch 2008|AA. Bibliography#Bloch 08]\] Item 8: Obey the general contract when overriding equals
\[[Darwin 2004|AA. Bibliography#Darwin 04]\] 9.2 Overriding the equals method
\[[Harold 1997|AA. Bibliography#Harold 97]\] Chapter 3: Classes, Strings, and Arrays, The Object Class (equality)
\[[Techtalk 2007|AA. Bibliography#Techtalk 07]\] "More Joy of Sets"
Wiki Markup
\[[API 2006|AA. Bibliography#API 06]\] [method equals()|http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#equals(java.lang.Object)]
\[[Bloch 2008|AA. Bibliography#Bloch 08]\] Item 8: Obey the general contract when overriding equals
\[[Darwin 2004|AA. Bibliography#Darwin 04]\] 9.2 Overriding the equals method

...

MET11-J. Never declare a class method that hides a method declared in a superclass or superinterface      05. Methods (MET)      MET13-J. Classes that define an equals() method must also define a hashCode() method