Even before the Log4j vulnerability led to the targeting of nearly one-half of global corporate networks, Java applications have presented abundant opportunities for hackers. After all, there are so many components to protect – server-side logic, client-side logic, data storage, data transportation, APIs and others – that it’s daunting to defend everything.
In fact, serious vulnerabilities exist within 44 percent of Java apps, compared to 23 percent in .NET ones. Fortunately, most vulnerabilities share the same root causes. But before you can fix them, you have to find them. And to find them, you have to know what you’re looking for. With this in mind, here’s our list of the top seven Java security pitfalls – and what you should do about them:
XXE attacks. This happens when cyber adversaries exploit an extensible markup language (XML) parser to read arbitrary files on your server. They can then deploy an XML external entity (XXE) to retrieve user information, configuration files or even credentials for cloud environments. Most Java XML parsers enable XXE requirements by default, so you should proactively disable these to avoid XXE attacks.
Insecure deserialization. During serialization, an object in a programing language is converted into a format that you can save to a database or transfer over a network. During deserialization, the opposite occurs: The serialized object is read from a file or network so you can convert it back into an object.
However, hackers will seek vulnerabilities in the form of insecure deserialization, so they can manipulate the serialized object to launch authentication bypass, denial of service or arbitrary code execution attacks.
To prevent this, you need to stay up-to-date with patches. You should also make sure your third-party code meets your standards for defense, because many insecure deserialization-caused vulnerabilities are introduced via dependencies.
Remote code execution. Hackers commit remote code execution (RCE) when they execute their code on your machine, often through command injection vulnerabilities – an RCE in which user input is linked directly to a system command. Your app can’t tell the difference between where the user input is and where the system command is, so it executes the user input as code. This allows the hackers to execute arbitrary commands on the machine.
Your best countermove here is to come up with an effective allowlist, which will ensure robust input validation.
SQL injection. Broadly defined, injections emerge when apps cannot properly distinguish between untrusted user data and legitimate/valid code. In operating system commands, this will lead to command injection.
In the case of structured query language (SQL) injections, adversaries inject data to manipulate SQL commands. If the app cannot validate user input properly, the adversaries will insert characters designated for the SQL language to disrupt the query’s logic and execute arbitrary SQL code. They can take advantage of the compromised query structure to modify or steal data and/or execute arbitrary commands in the operating system.
That’s why you have to leverage parameterized statements to make SQL injections virtually impossible, by pre-compiling SQL statements so you strictly supply the parameters (or variables/inputs) which you are seeking to insert into the statement to execute it.
NoSQL injection. “Not only SQL” (NoSQL) databases don’t use the SQL language. During NoSQL injections, hackers will inject data into the logic of the database languages to enable authentication bypasses and RCE. MongoDB, Couchbase, Cassandra, HBase and additional NoSQL databases are vulnerable to these attacks.
NoSQL query syntax is database-specific, and queries are often written in the programming language of the app. So you must resort to database-specific methods to block NoSQL injections. We’ve provided more detailed guidance on securing the individual, major databases here.
LDAP injection. Lightweight directory access protocol (LDAP) enables developers to query a directory service about a system’s users and devices. But when an app allows untrusted input in these queries, hackers can submit crafted inputs to bypass authentication and tamper with data stored in the directory. Again, parameterized queries remain effective in prevention here.
Log injection. Security teams rely on system logging to detect malicious activities in the network. But adversaries are aware of this, and will frequently alter log files to cover up their tracks during an attack. Through a typical log injection, they will trick the app into writing fake entries in your log files.
They may, for example, look for apps that do not sanitize new line characters in input written to logs, to introduce their own new line character and insert new app log entries. Or they will inject malicious HTML into log entries to launch a cross-site scripting (XSS) attack on the browser of the administrator who oversees the logs.
To avoid this, you need to distinguish between real log entries and fake ones, by prefixing each log entry with a timestamp, process ID, hostname and other forms of meta-data. In applying the principles of zero trust, you should treat log file content as untrusted input until you have fully validated it for access and operations.
The list of Java security pitfalls is hardly contained to these seven, as we are planning to publish in the near future an e-book with detailed summaries of 29 of the most common vulnerabilities. We are happy to provide this because, as the time-tested adage goes, knowledge is power. When teams are aware of what exists in their Java apps which could expose them, they are much closer to finding – and removing – the issues that leave them open to an attack.