Secure+Coding+in+C C+++Cheat+Sheet
Secure+Coding+in+C C+++Cheat+Sheet
1
fi
fi
Secure Coding in C/C++ Cheat Sheet
Input validation and sanitization, secure memory management, code reviews and testing and secure coding
practices can help you reduce the attack surface area of your code.
Least Privilege
The Principle of Least Privilege is a key concept in secure programming. It suggests only
granting the minimum necessary privileges required to do a speci c task. By limiting access
rights and privileges, the potential harm that can be caused by an attacker or compromised
component is greatly reduced.
Examples include limiting code permissions, controlling system calls, and restricting access
rights to the necessary minimum.
Fail-safe Defaults
The Principle of Fail-Safe Defaults suggests that access to resources and sensitive
operations must be denied by default. Access should only be granted explicitly with
permission.
To understand why this strategy is effective, consider the opposite scenario where access is
granted by default but turned off if certain conditions are met. In such a case, there is a higher
likelihood of overlooking critical conditions or failing to revoke access promptly, which can lead to potential
security breaches.
Defense in Depth
To secure your C and C++ applications, relying on a single security mechanism isn't enough.
A comprehensive approach is to use multiple layers of defense, known as "Defense in
Depth." By designing your system this way, attackers will have to overcome several security
measures, making it harder to compromise the system.
2
fi
Secure Coding in C/C++ Cheat Sheet
⚠
1 Buffer Over ows ⚠
2 Risky Type Conversions
✌ Solution 2
Alternatively, you can use snprintf() to avoid buffer
over ows. This function will also add the null
terminator automatically.
3
fl
fl
fl
fl
fl
fl
fi
fl
fl
fl
fl
fl
fl
fi
fi
fl
Secure Coding in C/C++ Cheat Sheet
⚠
3 Uncontrolled Format Strings ⚠
4 Improper Error Handling
When a program uses an Failing to handle errors properly can leave your code
unchecked format string as an vulnerable to security risks and impact program
argument to the printf() command reliability. Ignoring errors, failing to check the return
or similar functions, it can lead to values of functions that can fail, or exposing internal
the problem known as uncontrolled system details or valuable information in
format string, a common issue that error messages are common
can compromise security. mistakes in error management.
🦄 Exploitability 🦄 Exploitability
An attacker could use format strings as arguments Subpar error handling might
for printf() to reveal sensitive information stored in jeopardize the stability of your
memory or execute arbitrary code. application, and revealing con dential data could
offer hints to would-be attackers. Resource leaks
💥 Uncontrolled format string example could drain system capabilities and open the door to
The user_input string may include format speci ers possible denial-of-service risks.
like %s or %d, printf() will try to use additional
arguments that aren't there, resulting in unde ned 💥 Ignored error example
behavior. In the following code, the return value of fopen() is
not checked. If the le fails to open, the subsequent
And using the %x and %s format speci ers will call to fscanf() will read data from an uninitialized or
cause printf() to print out values from the stack, incorrect le stream, leading to unde ned behavior:
revealing sensitive information.
char buffer[MAX_BUFFER_SIZE];
FILE *file = fopen("data.txt", "r");
The %n speci er commands printf() to write the
number of characters successfully written so far to fscanf(file, "%s", buffer);
cout << "First word: " << buffer << endl;
an address pointed to by the corresponding
argument. As there's no corresponding argument, fclose(file);
printf() will write to whatever location is at the top of
the stack, leading to a potential security ✌ Solution
vulnerability. The improved code handles the failed le opening
// user_input may contain format specifiers scenario and logs the error:
printf(user_input);
char buffer[256];
FILE *file = fopen("data.txt", "r");
✌ Solution
if (!file)
Using printf("%s", user_input) prevents any format {
printf("Failed to open the file.\n");
speci ers in user_input from being interpreted by return;
printf(). }
4
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
Secure Coding in C/C++ Cheat Sheet
⚠
5 Race Conditions ✌ Solution
A race condition occurs when two Introduce a mutex and use std::lock_guard to lock
or more threads compete to and unlock the mutex during the critical section. This
access or modify shared data way we ensure that only one thread can access and
simultaneously. This can cause modify the counter variable at a time, preventing
sporadic bugs and severe security data corruption caused by a race condition.
vulnerabilities. Paying close
#include <iostream>
attention to concurrency and #include <thread>
handling it with care is crucial to avoid such risks. #include <mutex>
using namespace std;
int main()
💥 Race condition example {
thread t1(increment_counter);
In this example, both threads access and modify the thread t2(increment_counter);
counter variable simultaneously without proper t1.join();
synchronization. As a result, the integrity of the t2.join();
counter variable is compromised, potentially cout << "Counter value: " << counter << endl;
leading to incorrect program behavior and other
return 0;
issues. }
#include <iostream>
#include <thread>
using namespace std;
int counter = 0;
void increment_counter()
{
++counter;
}
int main()
{
thread t1(increment_counter);
thread t2(increment_counter);
t1.join();
t2.join();
return 0;
}
5
Secure Coding in C/C++ Cheat Sheet
⚠
6 C/C++ Memory Management Mistakes 💥 Referencing freed memory
Unlike other languages, C and In this code snippet, we rst allocate memory to store
C++ do not have automatic an integer and save the address of this memory block
garbage collection. Instead, in the variable value. Later, we free the allocated
developers must manage memory using the free() function.
memory manually—a powerful
Later, we attempt to write the value 5 to the same
but also risky feature. Thus, it’s
memory location that has already been freed. This
the responsibility of the
can cause unpredictable behavior and data
programmer to. Failure to do so can result in
corruption, as the memory block may now be used
vulnerabilities such as memory leaks, buffer
for other purposes by the system.
over ows, and dangling pointers.
int *value = malloc(sizeof(int)); // use new int()
🦄 Exploitability in C++
The side-effects of sloppy memory management free(value); // use operator delete in C++
// ... Perform some operations
can cause a wide range of problems with various // forget that value was freed and try to use it
degrees of severity, including: *value = 5;
6
fl
fi
fi
fi
fi
Secure Coding in C/C++ Cheat Sheet
Wrapping Up
Consider these examples as just a snapshot of what you've already encountered in the course on Secure
Coding in C/C++.
If you found these insights valuable and want to revisit any topics or perhaps share them with your
network, the course is always there for you to go through again.
Feel free to share this guide and the course link with others interested in upping their coding game.
Thanks again for being a part of this learning journey with me. Take care and happy coding! 😊
Best regards,
Karoly Nyisztor