1. 输入验证:严格过滤所有外部输入
所有用户输入(包括命令行参数、文件输入、网络数据、环境变量)必须经过严格验证,确保符合预期的格式、类型和长度。例如,使用std::string的length()方法限制输入长度(如if (input.length() > 100) { /* 拒绝过长输入 */ }),或通过正则表达式匹配合法字符集(如邮箱、手机号格式)。避免直接将未经验证的输入拼接到SQL语句、系统命令或文件路径中,防止SQL注入、命令注入和路径遍历攻击。
2. 内存管理:使用智能指针与标准库容器
优先使用C++标准库的智能指针(std::unique_ptr、std::shared_ptr)替代原始指针,实现自动内存管理,避免内存泄漏(如std::unique_ptr<int> ptr(new int(10));,离开作用域时自动释放内存)。使用std::vector、std::string等容器替代原生数组,容器会自动处理内存分配与边界检查(如std::vector<int> vec; vec.push_back(42);,无需手动管理容量)。禁止使用gets()、strcpy()、strcat()等不安全函数,若必须使用C风格字符串,需用strncpy()(指定最大长度)、snprintf()(限制输出大小)等安全替代函数,并手动添加字符串终止符\0。
3. 权限控制:遵循最小权限原则
程序运行时应以最低必要权限执行,避免以root用户启动。可通过以下方式限制权限:
setuid/setgid设置程序运行时的用户/组身份(如chmod u+s program,但需谨慎使用,避免权限提升漏洞);prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))限制程序可执行的操作(如禁止修改系统时间、加载内核模块);chroot或pivot_root隔离文件系统(如chroot("/safe/dir"),将程序限制在特定目录,无法访问系统其他部分);chmod 700 /path/to/sensitive/file,仅所有者可读写执行)。4. 安全函数与API:选择安全的替代方案
避免使用不安全的C风格函数,优先选择C++标准库或安全扩展函数:
std::string替代C风格字符串,或使用strncpy()(指定dest大小)、snprintf()(指定缓冲区大小);open()(指定O_CREAT|O_EXCL防止文件覆盖)替代fopen(),用read()/write()替代fread()/fwrite()(更底层,便于控制权限);std::ostringstream替代sprintf()(避免缓冲区溢出);new/delete配合智能指针,或直接使用std::vector/std::string。5. 错误处理:避免信息泄露与资源泄漏
检查所有系统调用(如open()、read())和库函数的返回值,确保操作成功(如int fd = open("file.txt", O_RDONLY); if (fd == -1) { /* 处理错误 */ })。使用C++异常处理机制捕获运行时错误(如try { /* 可能抛出异常的代码 */ } catch (const std::exception& e) { /* 记录错误但不泄露敏感信息 */ }),但需避免在异常处理中泄露敏感信息(如密码、密钥)。记录错误日志时,仅记录必要的上下文信息(如错误码、操作模块),不要记录用户输入或系统内部状态。
6. 并发编程:防止数据竞争与死锁
多线程环境下,使用std::mutex、std::lock_guard或std::unique_lock保护共享资源(如全局变量、文件句柄),避免数据竞争(如std::mutex mtx; { std::lock_guard<std::mutex> lock(mtx); shared_var++; })。优先使用std::atomic(如std::atomic<int> counter;)实现简单的原子操作,减少锁的开销。避免死锁:按固定顺序获取多个锁,或使用std::lock()同时获取多个锁(如std::lock(mtx1, mtx2);)。
7. 编译器与工具:启用安全选项与静态/动态分析
使用编译器安全选项增强代码安全性:
-Wall -Wextra:启用所有警告,捕捉潜在问题(如未初始化变量、数组越界);-fstack-protector-all:启用堆栈保护,防止栈溢出攻击;-fsanitize=address:启用地址消毒剂(AddressSanitizer),检测内存泄漏、越界访问;-D_FORTIFY_SOURCE=2:启用Fortify Source,检测缓冲区溢出(如strcpy()的溢出会被拦截)。clang-tidy、cppcheck)查找代码中的潜在安全漏洞(如未验证的输入、内存泄漏);使用动态分析工具(如valgrind)检测运行时错误(如内存泄漏、非法内存访问)。8. 日志与监控:记录安全事件与实时检测
实现详细的日志记录机制,记录用户操作、系统调用、错误信息等(如使用syslog或spdlog库),便于追踪安全事件(如syslog(LOG_INFO, "User %s logged in", username.c_str());)。保护日志文件的安全性:设置适当的权限(如chmod 600 /var/log/myapp.log),防止未授权访问;避免在日志中记录敏感信息(如密码、银行卡号)。使用实时监控工具(如auditd、sysdig)监控程序行为,及时发现异常(如频繁的文件访问、网络连接)。
9. 网络安全:使用加密协议与限制访问
网络通信必须使用TLS/SSL(如OpenSSL库)加密,防止数据泄露(如SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());)。限制网络访问权限:使用防火墙(如iptables、nftables)限制程序可访问的网络端口(如iptables -A INPUT -p tcp --dport 8080 -j ACCEPT),防止DDoS攻击。对网络输入数据进行验证(如HTTP请求的参数),防止网络注入攻击(如XSS、SQL注入)。
10. 代码审计与更新:定期检查与修复漏洞
定期进行代码审计:通过人工审查或自动化工具(如SonarQube)检查代码中的安全漏洞(如硬编码密码、未验证的输入)。及时更新系统和依赖库:使用包管理器(如apt、yum)更新操作系统和第三方库(如libssl),修复已知的安全漏洞(如sudo apt update && sudo apt upgrade)。定期进行渗透测试:模拟攻击者的行为(如SQL注入、缓冲区溢出),发现潜在的安全漏洞并及时修复。