C语言系列15——C语言的安全性与防御性编程
目录
- 写在开头
- 1 缓冲区溢出:如何防范与处理
- 1.1 缓冲区溢出的原因
- 1.2 预防与处理策略
- 2. 安全的字符串处理函数与使用技巧
- 2.1 `strncpy`函数
- 2.2 `snprintf`函数
- 2.3 `strlcpy`函数
- 2.4 使用技巧
- 3 防御性编程的基本原则与实际方法
- 3.1 基本原则
- 3.2 实际方法
- 写在最后
写在开头
在进行C语言编程时,我们时常需要面对各种安全性问题。其中最为常见的就是缓冲区溢出。本文将深入探讨缓冲区溢出的原因、安全的字符串处理函数以及防御性编程的实际方法,以期帮助读者更好地理解并应对C语言编程中的安全隐患。
1 缓冲区溢出:如何防范与处理
缓冲区溢出是指在程序中的某个缓冲区内写入了超出其预留空间的数据,导致数据覆盖了相邻内存区域的现象。这种情况可能会造成严重的安全漏洞,甚至使得攻击者能够利用漏洞来执行恶意代码,威胁系统的安全性。在C语言中,缓冲区溢出是一种常见的问题,因为C语言中的字符串通常是以空字符结尾的字符数组,而且C语言没有提供内置的边界检查机制。因此,程序员必须自己来确保不会发生缓冲区溢出,否则后果可能是灾难性的。
1.1 缓冲区溢出的原因
缓冲区溢出通常由以下原因引起:
-
未正确计算字符串长度:使用像
strcpy这样的字符串拷贝函数时,如果没有正确计算目标缓冲区的大小,就会导致溢出。例如,当源字符串的长度超过目标缓冲区的大小时,strcpy函数就会导致缓冲区溢出。 -
输入验证不足:在接受用户输入时,如果不对输入进行充分的验证和过滤,可能会导致恶意用户输入超出预期的长度,从而触发缓冲区溢出。
-
指针操作错误:对指针进行错误的操作也可能导致缓冲区溢出。例如,当程序员尝试通过指针来遍历数组时,如果没有正确地控制指针的范围,就可能导致指针越界,进而触发缓冲区溢出。
1.2 预防与处理策略
为了有效预防和处理缓冲区溢出问题,可以采取以下策略:
-
使用安全的字符串处理函数:使用像
strncpy、snprintf等安全的字符串处理函数来替代不安全的函数,这些函数可以确保在拷贝字符串时不会超出目标缓冲区的大小,从而有效地防止缓冲区溢出。 -
限制用户输入:在接受用户输入时,要对输入数据进行充分的验证和过滤,确保输入长度不会超出预期范围。可以使用函数如
fgets来限制输入的长度,或者使用正则表达式来验证输入的格式。 -
使用编译器和工具支持:现代编译器和静态分析工具通常提供了一些选项和工具来帮助检测和预防缓冲区溢出问题。例如,可以使用编译器选项开启堆栈保护、内存检查等功能,以及使用静态分析工具检测潜在的缓冲区溢出问题。
-
动态内存分配:尽量使用动态内存分配函数(如
malloc、calloc、realloc等)来分配内存,这样可以根据需要动态地分配内存空间,从而避免固定大小的缓冲区被溢出。
2. 安全的字符串处理函数与使用技巧
在C语言中,由于缺乏自动边界检查机制,使用传统的字符串处理函数可能会导致缓冲区溢出等安全问题。为了解决这些问题,许多安全的字符串处理函数被引入到了标准库中。这些函数可以确保在处理字符串时不会超出目标缓冲区的大小,从而有效地防止缓冲区溢出。
2.1 strncpy函数
strncpy函数是一个安全的字符串拷贝函数,它的原型如下:
char *strncpy(char *dest, const char *src, size_t n);
该函数将源字符串的前n个字符(不包括结尾的空字符)复制到目标字符串中,并在必要时添加空字符,以确保目标字符串以空字符结尾。这样,即使源字符串的长度超过了n,也不会导致缓冲区溢出。
2.2 snprintf函数
snprintf函数是一个安全的格式化输出函数,它的原型如下:
int snprintf(char *str, size_t size, const char *format, ...);
该函数类似于printf函数,但是它多了一个参数size,用来指定输出字符串的最大长度。如果输出字符串的长度超过了指定的最大长度,snprintf函数会截断多余的字符,从而避免缓冲区溢出。
2.3 strlcpy函数
strlcpy函数是一种安全的字符串拷贝函数,它的原型如下:
size_t strlcpy(char *dest, const char *src, size_t size);
该函数类似于strncpy函数,但是它会始终在目标缓冲区末尾添加空字符,以确保目标字符串以空字符结尾。与strncpy不同的是,strlcpy函数会确保目标缓冲区不会溢出,因此更安全可靠。
2.4 使用技巧
除了使用安全的字符串处理函数外,还有一些使用技巧可以帮助我们编写更安全的C代码:
-
避免使用不安全的函数:尽量避免使用不安全的字符串处理函数,如
strcpy、sprintf等,而是使用安全的替代函数。 -
始终检查返回值:在调用安全函数时,始终检查其返回值,以确保操作成功。例如,当
snprintf函数返回值等于缓冲区的大小减去1时,表示输出字符串被截断了。 -
正确计算字符串长度:在使用字符串处理函数时,确保正确计算源字符串的长度,以避免截断或溢出。
3 防御性编程的基本原则与实际方法
防御性编程是一种在软件开发过程中重要的思维方式,旨在预防和减轻软件系统中的安全风险。它的基本原则和实际方法有助于开发者有效地识别、预防和应对安全漏洞,从而提高软件系统的安全性和可靠性。
3.1 基本原则
-
最小特权原则:根据需要给予程序或用户最小的权限。这意味着限制程序或用户的访问范围,只给予其完成任务所需的最低权限,以降低潜在的安全风险。
-
输入验证:对所有输入数据进行有效的验证和过滤,以防止恶意输入导致的安全漏洞。这包括验证输入数据的长度、格式、类型等,确保输入符合预期,并能够安全地被处理。
-
错误处理:及时、有效地处理程序运行过程中出现的错误,防止错误被恶意利用或导致系统崩溃。正确的错误处理包括记录日志、返回合适的错误码、向用户提供友好的错误信息等。
3.2 实际方法
-
代码审查:定期进行代码审查是发现潜在安全问题的有效方法。通过对代码的仔细审查,可以及时发现并修复潜在的安全漏洞,提高代码的质量和安全性。
-
安全培训:加强开发人员的安全意识培训,提高其对安全性问题的认识和应对能力。培训内容包括安全编码规范、常见安全漏洞及防范措施等,帮助开发人员在编码过程中养成良好的安全习惯。
-
使用安全库和框架:借助现有的安全库和框架来加强系统的安全性。这些库和框架通常提供了各种安全功能,如加密解密、身份验证、访问控制等,能够帮助开发人员快速构建安全可靠的软件系统。
-
漏洞管理和应急响应:建立完善的漏洞管理和应急响应机制,及时跟踪和处理已知的安全漏洞,并制定相应的应对措施。同时,建立应急响应团队,提供及时、有效的应对措施,以降低已发现漏洞可能带来的风险。
写在最后
总结C语言编程中的安全性问题,我们必须认识到缓冲区溢出等问题的严重性,采取有效的预防和应对措施至关重要。通过使用安全的字符串处理函数、遵循防御性编程的基本原则以及不断加强安全意识培训,我们能够有效提高程序的安全性,保护用户数据和系统安全。防御性编程实践与案例分析将帮助开发者更深入地理解安全性问题,并掌握实际应对的方法,期待我们共同为构建安全可靠的软件而努力!
相关文章:
C语言系列15——C语言的安全性与防御性编程
目录 写在开头1 缓冲区溢出:如何防范与处理1.1 缓冲区溢出的原因1.2 预防与处理策略 2. 安全的字符串处理函数与使用技巧2.1 strncpy函数2.2 snprintf函数2.3 strlcpy函数2.4 使用技巧 3 防御性编程的基本原则与实际方法3.1 基本原则3.2 实际方法 写在最后 写在开头…...
objectMapper、ObjectNode、JsonNode调用接口时进行参数组装
objectMapper、ObjectNode、JsonNode用于调用接口时进行参数组装 public String sendText( List< String > listUser, String content ) throws JsonProcessingException{if ( listUser.size() < 0 ){return "用户ID为空!";}if ( content.lengt…...
2024开年,手机厂商革了自己的命
文|刘俊宏 编|王一粟 2024开年,AI终端的号角已经由手机行业吹响。 OPPO春节期间就没闲着,首席产品官刘作虎在大年三十就迫不及待地宣布,OPPO正式进入AI手机时代。随后在开年后就紧急召开了AI战略发布会,…...
【安全】大模型安全综述
大模型相关非安全综述 LLM演化和分类法 A survey on evaluation of large language models,” arXiv preprint arXiv:2307.03109, 2023.“A survey of large language models,” arXiv preprint arXiv:2303.18223, 2023.“A survey on llm-gernerated text detection: Necess…...
Stable Diffusion 模型分享:AstrAnime(Astr动画)
本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五 下载地址 模型介绍 AstrAnime 是一个动漫模型,画风色彩鲜明,擅长绘制漂亮的小姐姐。 条目内容类型大模型…...
【GPTs分享】每日GPTs分享之Canva
简介 Canva,旨在帮助用户通过Canva的用户友好设计平台释放用户的创造力。无论用户是想设计海报、社交媒体帖子还是商业名片,Canva都在这里协助用户将创意转化为现实。 主要功能 设计生成:根据用户的描述和创意需求,生成定制的设…...
【机器学习】数据清洗——基于Pandas库的方法删除重复点
🎈个人主页:豌豆射手^ 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:机器学习 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进…...
顺序表增删改查(c语言)
main函数: #include <stdio.h>#include "./seq.h"int main(int argc, const char *argv[]){SeqList* list create_seqList();insert_seqList(list,10);insert_seqList(list,100);insert_seqList(list,12);insert_seqList(list,23);show_seqList(l…...
MyBatis Plus中的动态表名实践
随着数据库应用的不断发展,面对复杂多变的业务需求,动态表名的处理变得愈发重要。在 MyBatis Plus(以下简称 MP)这一优秀的基于 MyBatis 的增强工具的支持下,我们可以更便捷地应对动态表名的挑战。本文将深入研究如何在…...
JAVA IDEA 项目打包为 jar 包详解
前言 如下简单 maven 项目,现在 maven 项目比较流行,你还没用过就OUT了。需要打包jar 先设置:点击 File > Project Structure > Artifacts > 点击加号 > 选择JAR > 选择From modules with dependencies 一、将所有依赖和模…...
概率基础——几何分布
概率基础——几何分布 介绍 在统计学中,几何分布是描述了在一系列独立同分布的伯努利试验中,第一次成功所需的试验次数的概率分布。在连续抛掷硬币的试验中,每次抛掷结果为正面向上的概率为 p p p,反面向上的概率为 1 − p 1-p …...
JavaScript的内存管理与垃圾回收
前言 JavaScript提供了高效的内存管理机制,它的垃圾回收功能是自动的。在我们创建新对象、函数、原始类型和变量时,所有这些编程元素都会占用内存。那么JavaScript是如何管理这些元素并在它们不再使用时清理它们的呢? 在本节中,…...
Neo4j导入数据之JAVA JDBC
目录结构 前言设置neo4j外部访问代码整理maven 依赖java 代码 参考链接 前言 公司需要获取neo4j数据库内容进行数据筛查,neo4j数据库咱也是头一次基础,辛辛苦苦安装好整理了安装neo4j的步骤,如今又遇到数据不知道怎么创建,关关难…...
LeetCode 2878.获取DataFrame的大小
DataFrame players: ------------------- | Column Name | Type | ------------------- | player_id | int | | name | object | | age | int | | position | object | | … | … | ------------------- 编写一个解决方案,计算并显示 players 的 行数和列数。 将结…...
索引失效的 12 种情况
目录 一、未使用索引字段进行查询 二、索引列使用了函数或表达式 三、使用了不等于(! 或 <>)操作符 四、LIKE 操作符的模糊查询 五、对索引列进行了数据类型转换 六、使用 OR 连接多个条件 七、表中数据量较少 八、索引列上存在大量重复值…...
Spring及工厂模式概述
文章目录 Spring 身世什么是 Spring什么是设计模式工厂设计模式什么是工厂设计模式简单的工厂设计模式通用的工厂设计 总结 在 Spring 框架出现之前,Java 开发者使用的主要是传统的 Java EE(Java Enterprise Edition)平台。Java EE 是一套用于…...
运维SRE-19 网站Web中间件服务-http-nginx
Ans自动化流程 1.网站集群核心协议:HTTP 1.1概述 web服务:网站服务,网站协议即可. 协议:http协议,https协议 服务:Nginx服务,Tengine服务....1.2 HTTP协议 http超文本传输协议,负责数据在网站…...
C语言—自定义(构造)类型
2.20,17.56 1.只有当我们使用结构体类型定义变量/结构体数组,系统才会为结构体的成员分配内存空间,用于存储对应类型的数据 2.strct 结构体 一起作为结构体类型标识符 嘿嘿暂时先这样,我会回来改的1、定义一个表示公交线路的结构体,要…...
ArcgisForJS如何实现添加含图片样式的点要素?
文章目录 0.引言1.加载底图2.获取点要素的坐标3.添加含图片样式的几何要素4.完整实现 0.引言 ArcGIS API for JavaScript 是一个用于在Web和移动应用程序中创建交互式地图和地理空间分析应用的库。本文在ArcGIS For JavaScript中使用Graphic对象来创建包含图片样式的点要素。 …...
C#之WPF学习之路(2)
目录 控件的父类 DispatcherObject类 DependencyObject类 DependencyObject 类的关键成员和方法 Visual类 Visual 类的主要成员和方法 UIElement类 UIElement 类的主要成员和功能 FrameworkElement类 FrameworkElement 类的主要成员和功能 控件的父类 在 WPF (Windo…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
es6+和css3新增的特性有哪些
一:ECMAScript 新特性(ES6) ES6 (2015) - 革命性更新 1,记住的方法,从一个方法里面用到了哪些技术 1,let /const块级作用域声明2,**默认参数**:函数参数可以设置默认值。3&#x…...
02.运算符
目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&:逻辑与 ||:逻辑或 !:逻辑非 短路求值 位运算符 按位与&: 按位或 | 按位取反~ …...
JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...
