【缺陷周话】第24期:在 scanf 函数中没有对 %s 格式符进行宽度限制
字数 902 2025-08-18 11:37:57
在scanf函数中没有对%s格式符进行宽度限制的安全缺陷分析
1. 缺陷概述
scanf()函数是C语言中常用的输入函数,当使用%s格式说明符时,如果没有对最大字段宽度进行限制,可能会导致缓冲区溢出漏洞。
相关函数
scanf()vscanf()fscanf()vsscanf()
2. 函数原型
int scanf(const char *restrict format, ...);
3. 格式说明符
常见格式说明符包括:
%c- 字符%d- 十进制整数%s- 字符串%o- 八进制整数%p- 指针%x/%X- 十六进制整数
4. %s格式符的行为
- 接收输入字符串并放入字符数组中
- 输入时以非空白字符串开始
- 以遇到第一个空白字符结束
- 匹配非空字符时使用字符指针指向数组
5. 安全风险
当使用%s格式说明符而没有限制最大字段宽度时:
- 输入长度可能超出目标缓冲区长度
- 导致缓冲区溢出
- 可能覆盖其他数据区
6. 示例代码分析
缺陷代码示例
fscanf(stream, "%s", a); // 没有对%s进行宽度限制
修复后的代码
fscanf(stream, "%100s", a); // 限制最大宽度为100字符
7. 检测方法
使用静态代码分析工具(如360代码卫士)可以检测此类问题:
- 检测等级:高
- 检测目标:查找未限制宽度的
%s格式符使用
8. 防御措施
-
限制宽度:在使用
%s时始终指定最大字段宽度scanf("%99s", buffer); // 对于100字节的缓冲区 -
使用更安全的替代函数:
fgets()+sscanf()- 特定平台的"安全"版本(如
scanf_s)
-
静态代码分析:
- 使用自动化工具定期扫描代码
- 在开发流程中集成安全检测
9. 最佳实践
- 避免在关键代码中使用
scanf()系列函数 - 如果必须使用,确保:
- 为所有
%s格式符指定最大宽度 - 宽度值应小于目标缓冲区大小(留出空字符空间)
- 为所有
- 进行边界测试,验证输入处理逻辑
- 在代码审查中特别检查输入处理函数的使用
10. 相关安全缺陷
其他类似的输入处理安全问题包括:
- 缓冲区上溢/下溢
- 命令注入
- SQL注入
- 路径遍历
- 整数溢出
11. 总结
scanf()系列函数中的%s格式符如果不加宽度限制,是常见的缓冲区溢出漏洞来源。开发人员应当:
- 始终为
%s指定最大宽度 - 考虑使用更安全的输入函数
- 通过自动化工具和代码审查确保安全性
- 遵循安全编码规范处理所有用户输入