当前位置: 首页 > news >正文

在写windows C++代码的时候,从代码安全角度考虑,我们应该注意什么?

        在写windows C++代码的时候,从代码安全角度考虑,我们应该注意什么?分别是:输入验证、内存管理、错误处理、并发和线程安全、使用安全的API、避免使用不安全的函数、最小权限原则。

一、输入验证

1. 用户输入验证

#include <iostream>
#include <string>
#include <limits>int main() {int age;while (true) {std::cout << "请输入您的年龄: ";if (std::cin >> age && age > 0 && age < 130) {break;} else {std::cout << "无效输入,请重新输入。\n";std::cin.clear(); // 清除失败的输入std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 忽略错误输入之后的字符}}std::cout << "输入的年龄是: " << age << std::endl;return 0;
}

2. 文件读取验证

        当从文件中读取数据时,您需要验证文件是否存在,是否可以被打开,以及读取的数据是否符合预期格式。例如,读取一个存储数字的文件:

#include <fstream>
#include <iostream>
#include <vector>int main() {std::ifstream file("numbers.txt");std::vector<int> numbers;int number;if (!file) {std::cerr << "无法打开文件" << std::endl;return 1;}while (file >> number) {numbers.push_back(number);}if (!file.eof()) {std::cerr << "文件读取过程中发生错误" << std::endl;return 1;}std::cout << "读取到的数字有: ";for (int num : numbers) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

3. 网络数据接收验证

        在处理网络通信时,接收到的数据应该经过严格验证。例如,如果您的程序是一个服务器,它可能需要验证从客户端接收到的消息格式是否正确:

// 假设这是一个简单的TCP服务器接收数据的代码片段
char buffer[1024];
int receivedBytes = recv(clientSocket, buffer, 1024, 0);
if (receivedBytes > 0) {// 验证接收到的数据if (isValidMessage(buffer, receivedBytes)) {// 处理消息} else {std::cerr << "接收到无效的消息格式" << std::endl;}
}

二、内存管理

1. 使用裸指针管理动态内存(传统方法)

int* ptr = new int(10); // 分配内存
// 使用 ptr...
delete ptr; // 释放内存
ptr = nullptr; // 防止悬挂指针

        在这个例子中,必须确保在 ptr 不再需要时释放分配的内存,并将指针设为 nullptr 以避免悬挂指针。这种方法容易出错,因为需要手动管理内存。

2. 使用智能指针管理动态内存(现代方法)

        C++11 引入的智能指针(如 std::unique_ptrstd::shared_ptr)自动管理内存,可以减少内存泄漏的风险。

#include <memory>std::unique_ptr<int> ptr(new int(10));
// 使用 ptr...
// 不需要手动释放内存,当 ptr 离开作用域时,内存会自动被释放

3. 防止数组越界

4. 避免内存泄漏

void function() {int* ptr = new int(10); // 分配内存// 函数的其他操作...delete ptr; // 释放内存
}

        如果函数中有多个返回路径或可能抛出异常,使用智能指针来保证内存在任何情况下都能被正确释放。

三、错误处理机制

1. 使用异常处理机制

        C++ 提供了异常处理机制,允许在检测到错误时抛出异常,并在上层代码中捕获和处理这些异常。

#include <iostream>
#include <stdexcept>double divide(double a, double b) {if (b == 0) {throw std::invalid_argument("除数不能为0");}return a / b;
}int main() {try {double result = divide(10.0, 0.0);std::cout << "结果: " << result << std::endl;} catch (const std::invalid_argument& e) {std::cerr << "捕获到错误: " << e.what() << std::endl;}return 0;
}

2. 使用返回值进行错误指示

        在某些情况下,使用返回值来指示错误是更加合适的。这种方法常用于 C 风格的代码或者需要保持与旧代码的兼容性。

#include <iostream>bool safeDivide(double a, double b, double& result) {if (b == 0) {return false; // 错误指示}result = a / b;return true; // 操作成功
}int main() {double result;if (!safeDivide(10.0, 0.0, result)) {std::cerr << "错误:除数不能为0" << std::endl;} else {std::cout << "结果: " << result << std::endl;}return 0;
}

3. 使用错误码

四、最小权限原则

        最小权限原则(Principle of Least Privilege, PoLP)是一种安全设计原则,意在确保程序、进程或用户仅具有完成其任务所必需的最小权限集。在 Windows C++ 编程中,这通常涉及到操作系统资源的访问和管理。以下是一些应用最小权限原则的例子:

1. 运行权限限制

        当开发一个应用程序时,确保它以最低必要的权限运行。例如,如果您的程序仅需读取文件,不应请求或具有写入文件的权限。

// 以只读方式打开文件
std::ifstream file("example.txt");
if (!file) {std::cerr << "无法打开文件,权限不足或文件不存在" << std::endl;// 错误处理
}

2. 数据库访问

        当您的程序需要与数据库交互时,为数据库用户分配只能执行其需求的操作的最小权限。例如,如果程序只需要从数据库读取数据,那么数据库用户不应该具有写入、修改或删除数据的权限。

// 假设这是一个数据库连接代码片段
// 这个数据库用户只有读取数据的权限
const char* connectionString = "User=ReadOnlyUser;Password=example;...";

3. 网络服务权限

        如果您的程序是一个网络服务,确保它在一个受限的环境中运行,例如在低权限的用户账户下运行,避免在需要管理员权限的账户下运行。

4. 文件和目录权限

        当您的程序需要创建文件或目录时,设置合理的访问控制列表(ACL),以确保只有必要的用户或程序有权访问这些资源。

五、并发和线程安全

        在并发编程中,线程安全是一个核心考虑因素。线程安全的代码可以在多线程环境中安全地被多个线程同时执行,而不会导致数据损坏或不一致的状态。以下是一些并发和线程安全的例子:

1. 使用互斥锁

        互斥锁(mutex)是保护共享资源免受多个线程同时访问的一种方法。

#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx; // 全局互斥锁
int sharedData = 0; // 共享数据void increment() {mtx.lock(); // 获取锁++sharedData; // 修改共享数据mtx.unlock(); // 释放锁
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout << "共享数据的值: " << sharedData << std::endl;return 0;
}

2. 使用条件变量

        条件变量是一种允许线程等待特定条件的同步机制。

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>std::mutex mtx;
std::condition_variable cv;
bool ready = false;void printNumber(int num) {std::unique_lock<std::mutex> lck(mtx);while (!ready) {cv.wait(lck);}std::cout << "Number: " << num << std::endl;
}void setReady() {{std::lock_guard<std::mutex> lck(mtx);ready = true;}cv.notify_all();
}int main() {std::thread t1(printNumber, 1);std::thread t2(printNumber, 2);setReady();t1.join();t2.join();return 0;
}

        在这个例子中,两个线程等待 ready 变量变为 true。一旦 setReady 函数被调用,条件变量通知所有等待的线程继续执行。

3. 使用原子操作

        原子操作是不可分割的操作,可以在多线程环境中安全地执行,不需要额外的同步机制。

#include <iostream>
#include <thread>
#include <atomic>std::atomic<int> count(0); // 原子变量void increment() {for (int i = 0; i < 10000; ++i) {count++; // 原子操作}
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout << "计数: " << count << std::endl;return 0;
}

        在这个例子中,两个线程同时增加一个计数器。由于 count 是一个原子类型,每次增加操作都是线程安全的。

六、使用安全的函数(Windows api)

        这里只需注意需要使用安全的。

1. 字符串复制

char source[] = "Hello World";
char dest[11];
strcpy(dest, source); // 不安全,没有边界检查char source[] = "Hello World";
char dest[11];
strncpy(dest, source, sizeof(dest) - 1); // 安全,指定最大复制长度
dest[sizeof(dest) - 1] = '\0'; // 确保字符串以空字符结尾

strcpy 的问题

  strcpy 函数用于将一个字符串复制到另一个字符串。它继续复制字符直到遇到源字符串的空终止字符('\0')。这个函数的问题在于它不考虑目标字符串的大小。如果源字符串长度超过了目标字符串的容量,strcpy 会继续写入,导致超出目标数组的边界,造成缓冲区溢出。这种溢出可能覆盖其他重要的内存数据,引起程序崩溃或安全漏洞。

        char source[] = "这个字符串很长,超过目标缓冲区的大小"; char dest[10]; // 只有10个字符的空间 strcpy(dest, source); // 危险:源字符串长度超过了dest的容量

        在这个例子中,dest 只能容纳9个字符和一个空终止符,但 source 的长度远远超过这个限制,导致 dest 的边界被溢出。

strncpy 的相对安全性

  strncpy 函数也是用于复制字符串,但它接受一个额外的参数来指定最大复制的字符数。这个函数在到达最大字符数或遇到源字符串的空终止符时停止复制。这有助于防止超出目标数组的边界,如果正确使用的话。

char source[] = "这个字符串很长,可能超过目标缓冲区的大小";
char dest[10];
strncpy(dest, source, sizeof(dest) - 1); // 复制最多9个字符
dest[sizeof(dest) - 1] = '\0'; // 确保有空终止符

strcpy 的问题

strcpy 函数用于将一个字符串复制到另一个字符串。它继续复制字符直到遇到源字符串的空终止字符('\0')。这个函数的问题在于它不考虑目标字符串的大小。如果源字符串长度超过了目标字符串的容量,strcpy 会继续写入,导致超出目标数组的边界,造成缓冲区溢出。这种溢出可能覆盖其他重要的内存数据,引起程序崩溃或安全漏洞。

strncpy 的相对安全性

strncpy 函数也是用于复制字符串,但它接受一个额外的参数来指定最大复制的字符数。这个函数在到达最大字符数或遇到源字符串的空终止符时停止复制。这有助于防止超出目标数组的边界,如果正确使用的话。

例子:使用 strncpy 防止缓冲区溢出

2. 字符串连接

char str[10] = "Hello";
strcat(str, " World"); // 不安全,可能导致缓冲区溢出char str[15] = "Hello";
strncat(str, " World", sizeof(str) - strlen(str) - 1); // 安全,限制最大添加长度

3. 格式化字符串

char buffer[50];
sprintf(buffer, "Value: %d", 123); // 不安全,没有边界检查char buffer[50];
snprintf(buffer, sizeof(buffer), "Value: %d", 123); // 安全,限制最大写入长度

        虽然 strncpystrcpy 安全,但它仍然需要小心使用。如果最大复制长度小于源字符串长度,strncpy 不会自动添加空终止符,可能导致目标字符串没有正确终止。因此,使用 strncpy 时,程序员需要确保目标字符串有足够的空间,并在需要时手动添加空终止符。

 

相关文章:

在写windows C++代码的时候,从代码安全角度考虑,我们应该注意什么?

在写windows C代码的时候&#xff0c;从代码安全角度考虑&#xff0c;我们应该注意什么&#xff1f;分别是&#xff1a;输入验证、内存管理、错误处理、并发和线程安全、使用安全的API、避免使用不安全的函数、最小权限原则。 一、输入验证 1. 用户输入验证 #include <io…...

【草料】uni-app ts vue 小程序 如何如何通过草料生成对应的模块化二维码

一、查看uni-app项目 1、找到路径 可以看到项目从 src-race-pages-group 这个使我们目标的查询页面 下面我们将这个路径copy到草料内 2、找到进入页面入参 一般我们都会选择 onload() 函数下的入参 这里我们参数的是 id 二、草料 建议看完这里的教程文档 十分清晰&#xff01…...

CMS与FullGC

JVM中的CMS&#xff08;Concurrent Mark Sweep&#xff09;GC和Full GC&#xff08;Full Garbage Collection&#xff09;是两种不同的垃圾回收算法。 CMS GC&#xff1a;CMS GC是一种并发的垃圾回收算法&#xff0c;它在运行期间与应用程序线程并发工作&#xff0c;尽可能减少…...

一款.NET开源的小巧、智能、免费的Windows内存清理工具 - WinMemoryCleaner

前言 我们在使用Windows系统的时候经常会遇到一些程序不会释放已分配的内存&#xff0c;从而导致电脑变得缓慢。今天给大家推荐一款.NET开源的小巧、智能、免费的Windows内存清理工具&#xff1a;WinMemoryCleaner。 使用Windows内存清理工具来优化内存&#xff0c;这样不必浪…...

iptables详解:链、表、表链关系、规则的基本使用

目录 防火墙基本概念 什么是防火墙&#xff1f; Netfilter与iptables的关系 链的概念 表的概念 表链关系 规则的概念 查询规则 添加规则 删除iptables中的记录 修改规则 更详细的命令&#xff08;5链4表&#xff09; 防火墙基本概念 什么是防火墙&#xff1f; 在…...

安全管理中心(设备和技术注解)

网络安全等级保护相关标准参考《GB/T 22239-2019 网络安全等级保护基本要求》和《GB/T 28448-2019 网络安全等级保护测评要求》 密码应用安全性相关标准参考《GB/T 39786-2021 信息系统密码应用基本要求》和《GM/T 0115-2021 信息系统密码应用测评要求》 1系统管理 1.1对系统管…...

Failed to execute org.scala-tools:maven-scala-plugin:2.15.2解决

原因也不是很清楚&#xff0c;查看一个博主文章(net.alchim31.maven:scala-maven-plugin&#xff1a;maven依赖无法下载或无法编译)得到的解决方案&#xff1a; 在idea的terminal执行以下语句即可实现maven对scala代码的编译&#xff1a; mvn clean scala:compile compile pac…...

C#中委托和事件的使用总结

委托&#xff08;delegate&#xff09;特别用于实现事件和回调方法。所有的委托&#xff08;Delegate&#xff09;都派生自 System.Delegate 类。事件是一种特殊的多播委托&#xff0c;仅可以从声明事件的类或结构中对其进行调用。类或对象可以通过事件向其他类或对象通知发生的…...

基于STM32的外部中断(EXTI)在嵌入式系统中的应用

外部中断&#xff08;External Interrupt&#xff0c;EXTI&#xff09;是STM32嵌入式系统中常见且重要的功能之一。它允许外部事件&#xff08;例如按键按下、传感器触发等&#xff09;通过适当的引脚触发中断&#xff0c;从而应用于各种嵌入式系统中。在STM32微控制器中&#…...

【心得】PHP的文件上传个人笔记

目录 1 php的文件上传绕过 黑名单绕过 2 php文件上传的00截断 3 iconv字符转换异常后造成了字符截断 4 文件后缀是白名单的时候的绕过 web服务器的解析漏洞绕过 5.高级文件上传绕过 1 .htaccess nginx.htaccess 2 服务端内容检测 3 配合伪协议来绕过 4.配合日志包含绕…...

深度学习之基于Pytorch和OCR的识别文本检测系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介深度学习与OCRPyTorch在OCR中的应用文本检测系统的关键组成部分1. 图像预处理2. 深度学习模型3. 文本检测算法4. 后处理 二、功能三、系统四. 总结 一项目简…...

三十一、W5100S/W5500+RP2040树莓派Pico<TCP_Server多路socket>

文章目录 1 前言2 简介2. 1 使用多路socket的优点2.2 多路socket数据交互原理2.3 多路socket应用场景 3 WIZnet以太网芯片4 多路socket设置示例概述以及使用4.1 流程图4.2 准备工作核心4.3 连接方式4.4 主要代码概述4.5 结果演示 5 注意事项6 相关链接 1 前言 W5100S/W5500是一…...

带你精通chrony服务器

华子目录 为什么会出现Chrony&#xff1f;Linux的两个时钟NTP介绍Chrony介绍安装与配置安装Chrony配置文件分析实验1实验2chronyc命令查看时间服务器chronyc sources输出分析其他命令 常见时区 为什么会出现Chrony&#xff1f; 由于IT系统中&#xff0c;准确的计时非常重要&am…...

vs2017 编译Qt 5.11.2 源码

SDK 10.0.22000.194 有 2种编译方式 &#xff0c;第二种 看下面 方式一: 1、问题描述&#xff1a; 使用VS编译程序时&#xff0c;运行库选择多线程&#xff08;/MT&#xff09;&#xff0c;表示采用多线程静态release的方式进行编译。 但是&#xff0c;发现编译是不能通过的…...

【SpringBoot3+Vue3】四【实战篇】-前端(vue基础)

目录 一、项目前置知识 二、使用vscode创建 三、vue介绍 四、局部使用vue 1、快速入门 1.1 需求 1.2 准备工作 1.3 操作 1.3.1 创建html 1.3.2 创建初始html代码 1.3.3 参照官网import vue 1.3.4 创建vue应用实例 1.3.5 准备div 1.3.6 准备用户数据 1.3.7 通过…...

element ui修改select选择框背景色和边框色

一、修改选择框的背景色和边框色 style部分 .custom-select /deep/ .el-input__inner {color: #fff!important;border: 1px solid #326AFF;background: #04308D !important; } html部分 <el-select class"custom-select" v-model"dhvalue" placeholde…...

软件测试人员提问常用的ChatGPT通用提示词模板

如何设计有效的软件测试用例&#xff1f; 如何运用自动化测试工具进行软件测试&#xff1f; 如何进行软件的功能测试、性能测试和安全测试&#xff1f; 如何评估软件测试的质量和覆盖范围&#xff1f; 软件测试有哪些常见的缺陷和错误&#xff0c;如何识别和解决&#xff1…...

【开源】基于JAVA的服装店库存管理系统

项目编号&#xff1a; S 052 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S052&#xff0c;文末获取源码。} 项目编号&#xff1a;S052&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 角色管理模块2.3 服…...

Jenkins代码检测和本地静态检查

1&#xff1a;Jenkins简介 Jenkins是一个用Java编写的开源的持续集成工具&#xff1b;Jenkins自动化部署可以解决集成、测试、部署等重复性的工作&#xff0c;工具集成的效率明显高于人工操作&#xff1b;并且持续集成可以更早的获取代码变更的信息&#xff0c;从而更早的进入测…...

从0开始学习JavaScript--JavaScript 字符串与文本内容使用

JavaScript中的字符串和文本内容处理是前端开发中的核心技能之一。本文将深入研究字符串的创建、操作&#xff0c;以及文本内容的获取、修改等操作&#xff0c;并通过丰富的示例代码&#xff0c;帮助读者更全面地了解和应用这些概念。 JavaScript 字符串基础 字符串是JavaScr…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏

一、引言 在深度学习中&#xff0c;我们训练出的神经网络往往非常庞大&#xff08;比如像 ResNet、YOLOv8、Vision Transformer&#xff09;&#xff0c;虽然精度很高&#xff0c;但“太重”了&#xff0c;运行起来很慢&#xff0c;占用内存大&#xff0c;不适合部署到手机、摄…...

【深度学习新浪潮】什么是credit assignment problem?

Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...

前端高频面试题2:浏览器/计算机网络

本专栏相关链接 前端高频面试题1&#xff1a;HTML/CSS 前端高频面试题2&#xff1a;浏览器/计算机网络 前端高频面试题3&#xff1a;JavaScript 1.什么是强缓存、协商缓存&#xff1f; 强缓存&#xff1a; 当浏览器请求资源时&#xff0c;首先检查本地缓存是否命中。如果命…...

从零手写Java版本的LSM Tree (一):LSM Tree 概述

&#x1f525; 推荐一个高质量的Java LSM Tree开源项目&#xff01; https://github.com/brianxiadong/java-lsm-tree java-lsm-tree 是一个从零实现的Log-Structured Merge Tree&#xff0c;专为高并发写入场景设计。 核心亮点&#xff1a; ⚡ 极致性能&#xff1a;写入速度超…...

华为OD机考- 简单的自动曝光/平均像素

import java.util.Arrays; import java.util.Scanner;public class DemoTest4 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint[] arr Array…...

前端打包工具简单介绍

前端打包工具简单介绍 一、Webpack 架构与插件机制 1. Webpack 架构核心组成 Entry&#xff08;入口&#xff09; 指定应用的起点文件&#xff0c;比如 src/index.js。 Module&#xff08;模块&#xff09; Webpack 把项目当作模块图&#xff0c;模块可以是 JS、CSS、图片等…...