Jan had been tasked with digging into a Java web application exhibiting odd behavior. New users couldn’t create accounts, and existing users sometimes found themselves logged in as other people. Concern about sensitive personal data being exposed to the wrong individuals had raised many corporate hackles, especially within the Legal department. While unresolved, the issue left the company open to litigation.
It was easy to rule out a state management issue. After that, Jan traced a typical login, and noticed something odd. The ID for his test account was 102, a value that came from an autonumbered column in the backend database. However, the application had to pass user data to an external vendor’s iFrame, which had its own mechanism for handling user states. Inside the iFrame, Jan’s ID was 48627.
The value 48627 didn’t exist anywhere in the local database. Jan dug into the application source code, and found this line:
url = iFrameUrl.replaceAll("user=","user=" + user.hashCode());
Digging deeper, the hashCode() method for the user class looked like this:
public int hashCode() {
return String.valueOf(getId()).hashCode();
}
Therefore, Jan’s local ID- a long- was being converted into a String and then hashed. Sure enough, when Jan ran:
System.out.println("102".hashCode());
The result was 48627
.
Jan checked source control, found the name of the contractor responsible- Anders- and arranged a visit. “Why?” he begged to know.
“The external vendor needs small IDs,” Anders told him. “This way we ensure we never send a value bigger than 32768.”
Jan’s brain seized up. It was a few moments before he could resume speaking without a torrent of profanity. “OK, that’s a stupid limit- but worse, this hash code thing is already exceeding it. New user accounts can’t be created. Besides, did it ever occur to you that Strings don’t hash perfectly? Two user IDs can, and have, hashed to the same value!”
Anders shrugged. “Code’s in production, man. Have the users log a ticket.”
Jan didn’t have the opportunity to lose any more neurons over the implications. Before he could put a more sensible solution in place, he was let go and replaced by a contractor- not Anders, but a different fellow from the same contracting firm, who eventually “fixed” the issue to the tune of a $140K lawsuit.