C++ 应用程序安全:十大漏洞及防护方法
C++ 是一种强大的系统编程语言,但其灵活性和直接内存访问能力使应用程序容易受到严重攻击。根据 OWASP 和 CWE,工业软件(从游戏到航空电子设备)中的许多关键漏洞正是由 C++ 代码错误引起的。在本文中,我们将分析十大最危险的漏洞,提供代码示例,并展示如何避免它们。
1. 缓冲区溢出
一种经典漏洞,允许攻击者覆盖相邻的内存区域。它发生在未检查大小的情况下复制数据时。
// Vulnerable code#include <cstring>void vulnerable(char* input) { char buffer[10]; strcpy(buffer, input); // Danger: if input is longer than 9 characters}// Secure versionvoid secure(char* input, size_t len) { char buffer[10]; if (len < sizeof(buffer)) { strncpy(buffer, input, sizeof(buffer) - 1); buffer[sizeof(buffer) - 1] = '\\0'; }}防护方法:使用 std::string、std::vector 或长度限制函数(strncpy、snprintf)。启用编译器标志 -fstack-protector-strong 和 -D_FORTIFY_SOURCE=2。
2. 释放后使用
访问已经释放的内存。导致在另一个区域读写或执行任意代码。
// Vulnerable codeint* ptr = new int(42);delete ptr;*ptr = 100; // Error! ptr is no longer valid// Secure versionint* ptr = new int(42);delete ptr;ptr = nullptr; // Nullify the pointerif (ptr) *ptr = 100; // Check before use防护方法:使用智能指针(std::unique_ptr、std::shared_ptr),在 delete 后将原始指针置空,应用清理工具(-fsanitize=address)。
3. 整数溢出
算术运算期间超出允许范围。常用于绕过缓冲区大小检查。
// Vulnerable codesize_t size = 0;size_t user_input = 4294967295; // 2^32 - 1size_t total = size + user_input + 1; // Overflow!// Secure version with checkif (user_input > SIZE_MAX - size) { throw std::overflow_error("Size too large");}size_t total = size + user_input + 1;防护方法:使用固定宽度类型(uint32_t),在操作前检查溢出,使用 __builtin_add_overflow(GCC/Clang)。
4. 空指针解引用
尝试访问 NULL 地址处的内存。导致程序崩溃(段错误)或 DoS 漏洞。
// Vulnerable codevoid process(int* ptr) { *ptr = 10; // If ptr == nullptr — crash}// Secure versionvoid process(int* ptr) { if (!ptr) { throw std::invalid_argument("Null pointer received"); } *ptr = 10;}防护方法:使用前始终检查指针是否为 nullptr,返回 std::optional 而不是原始指针。
5. 内存泄漏
丢失对已分配内存的访问而不释放。随着时间的推移,会耗尽系统资源。
// Vulnerable codevoid leak() { int* data = new int[100]; // Forgot delete[] data — leak}// Secure versionvoid no_leak() { std::unique_ptr<int[]> data = std::make_unique<int[]>(100); // Memory will be freed automatically}防护方法:使用 RAII(智能指针、容器)