My Top 6 Common Weaknesses Every Programmer Should Know By Heart

in secure code

Common Weakness Enumeration, or in its short name CWE, lists about 700 common mistakes developers make while writing code. Remembering or even reading the entire list can be a challenge. But there are some repeating ideas that due to their massive potential impact it is important to know (and tell your friends) about.

Injections

The first is of course injections, which in their many forms have caused chaos throughout the industry. Not long ago the entire internet was vulnerable to CWE-89 - SQL Injection. Today CWE-79 - Cross Site Scripting is still causing havoc and will continue to do so until we'll all move to CSP.

Another one from the same category is CWE-78 - OS Command Injection which talks about injecting OS commands through shell escapes. A vulnerable PHP code looks like this:

$userName = $_POST["user"];
$command = 'ls -l /home/' . $userName;
system($command);

Just consider what happens when the input is ;rm -rf /

Path Traversal

CWE-22 - Path Traversal is one of the first CWEs I learned about, and its simplicity is what makes it beautiful. This following java code thinks it will only delete files from a specified safe dir:

String path = getInputPath();
if (path.startsWith("/safe_dir/"))
{
    File f = new File(path);
    f.delete()
}

But consider its result when the path parameter is /safe_dir/../important.dat. When reading path from a user always use a built-in path canonicalization function to produce a canonical version of the file name or path. In Java that would be getCanonicalPath.

Insufficient Verification of Data Authenticity

CWE-345 is by far the most complex in this list as it is a parent of many other weaknesses. Its main gist is that you must never assume a request or data came from a specific user, and must validate the data before using it.

I think the most known child of this weakness is CSRF, which is caused by a request sent with the correct cookies but in the wrong context.

Another example is the padding oracle attack which was made possible due to improper verification of the encrypted data's signature, and assuming that if we get an encrypted packet then a trusted partner must have sent it (forgetting that adversaries can change the bits on the wire).

Race Condition

The Famous CWE-362 is easy to ignore just as it is easy to understand. When writing code too many developers forget to consider what would happen if the code ran concurrently, which is just the way most server code is executed.

Consider the code example from the CWE page:

$transfer_amount = GetTransferAmount();
$balance = GetBalanceFromDatabase();

if ($transfer_amount < 0) {
    FatalError("Bad Transfer Amount");
}

$newbalance = $balance - $transfer_amount;
if (($balance - $transfer_amount) < 0) {
    FatalError("Insufficient Funds");
}

SendNewBalanceToDatabase($newbalance);
NotifyUser("Transfer of $transfer_amount succeeded.");
NotifyUser("New balance: $newbalance");

Looks good until one asks - what happens when this code is executed from multiple threads or processes? The answer is we don't know. It could work, or it could give too much money to one side, as Starbucks had unfortunately found.

Your language probably has transactions and locking mechanisms to protect against such cases. Use them.

Password in Configuration File

CWE-260: Password in Configuration File is almost too universal to be angry about, but we still should.

Passwords should not be stored in the same file as your DB connection strings or other network data, or in any configuration file. Those files are hard to protect and tend to be sent around.

Better to create a dedicated secrets file which will store all application secrets, or to use environment variables.

Keep your secrets secret and share configuration only.

Stack-based Buffer Overflow

At first I intended to finish here with the 5 most important CWEs presented above, but we can't ignore the famous CWE-121: Stack-based Buffer Overflow, due to its history and its insight.

This bug is probably very hard to exploit on modern systems due to ASLR, Non Execute Stack and Stack Protector features. But it was the seed for too many memory and buffer overflows we still encounter today.

Go read about it in the above link and later read and follow Paul Makowski's modern smashing the stack for fun and profit if you're not already familiar with that work.

Comments