当前位置: 首页 > 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…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

云计算——弹性云计算器(ECS)

弹性云服务器&#xff1a;ECS 概述 云计算重构了ICT系统&#xff0c;云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台&#xff0c;包含如下主要概念。 ECS&#xff08;Elastic Cloud Server&#xff09;&#xff1a;即弹性云服务器&#xff0c;是云计算…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...