《华章程序员书库:C和C++安全编码(原书第2版)》是C/C++安全编码领域的权威著作,被视为“标准”参考书,由国际资深软件安全专家撰写,美国CERT主管亲自作序推荐。本书结合国际标准C11和C++11,以及C和C++语言的最新发展,既详细阐述了C/C++语言及其相关库固有的安全问题和陷阱,系统总结了导致软件漏洞的各种常见编码错误,并给出了应对错误的解决方案;又对C/C++软件中常见漏洞的危害、被利用方式、检测方法和应对之道进行了全方位讲解,包含大量编码练习,实践性强。《华章程序员书库:C和C++安全编码(原书第2版)》从C和C++语言的各个部分分别介绍了可能导致安全问题的软件漏洞:第1章介绍安全术语和概念,并指出为何C和C++程序中存在如此多的漏洞。第2章描述C和C++中的字符串操作、常见的安全缺陷以及由此导致的漏洞。第3章介绍任意内存写漏洞利用方式,它允许攻击者对内存中任意位置的一个地址进行写操作。第4章描述动态内存管理,讨论了动态分配的缓冲区溢出、写入已释放内存,以及重复释放漏洞。第5章讨论整数安全问题(即与整数操作相关的安全议题),包括整数溢出、符号错误以及截断错误等。第6章描述格式化输出函数的正确和错误的用法,对因这些函数的错误使用所导致的格式字符串和缓冲区溢出漏洞都有讨论。第7章重点介绍并发和可能导致死锁、竞争条件和无效的内存访问序列的漏洞。第8章描述和文件I/O相关的常见漏洞,包括竞争条件和检查时间与使用时间漏洞。第9章推荐一些可以整体改善C/C++应用程序安全性的具体开发实践,这些建议是对每一章中用于解决特定漏洞问题的推荐做法的补充。
目录
- 译者序
- 序
- 前言
- 致谢
- 第1章夹缝求生
- 1.1 衡量危险
- 1.1.1 损失的现状
- 1.1.2 威胁的来源
- 1.1.3 软件安全
- 1.2 安全概念
- 1.2.1 安全策略
- 1.2.2 安全缺陷
- 1.2.3 漏洞
- 1.2.4 漏洞利用
- 1.2.5 缓解措施
- 1.3 C和C++
- 1.3.1 C和C++简史
- 1.3.2 C存在的问题
- 1.3.3 遗留代码
- 1.3.4 其他语言
- 1.4 开发平台
- 1.4.1 操作系统
- 1.4.2 编译器
- 1.5 小结
- 1.6 阅读材料
- 第2章字符串
- 2.1 字符串
- 2.1.1 字符串数据类型
- 2.1.2 UTF-8
- 2.1.3 宽字符串
- 2.1.4 字符串字面值
- 2.1.5 C++中的字符串
- 2.1.6 字符类型
- 2.1.7 计算字符串大小
- 2.2 常见的字符串操作错误
- 2.2.1 无界字符串复制
- 2.2.2 差一错误
- 2.2.3 空字符结尾错误
- 2.2.4 字符串截断
- 2.2.5 与函数无关的字符串错误
- 2.3 字符串漏洞及其利用
- 2.3.1 被污染的数据
- 2.3.2 IsPasswordOK的安全缺陷
- 2.3.3 缓冲区溢出
- 2.3.4 进程内存组织
- 2.3.5 栈管理
- 2.3.6 栈溢出
- 2.3.7 代码注入
- 2.3.8 弧注入
- 2.3.9 返回导向编程
- 2.4 字符串漏洞缓解策略
- 2.4.1 字符串处理
- 2.4.2 C11附录K边界检查接口
- 2.4.3 动态分配函数
- 2.4.4 C++ std::basic_string
- 2.4.5 使字符串对象的引用失效
- 2.4.6 使用basic_string的其他常见错误
- 2.5 字符串处理函数
- 2.5.1 gets
- 2.5.2 C99
- 2.5.3 C11附录K边界检查接口:gets-s
- 2.5.4 动态分配函数
- 2.5.5 strcpy和strcat
- 2.5.6 C99
- 2.5.7 strncpy和strncat
- 2.5.8 memcpy和memmove
- 2.5.9 strlen
- 2.6 运行时保护策略
- 2.6.1 检测和恢复
- 2.6.2 输入验证
- 2.6.3 对象大小检查
- 2.6.4 Visual Studio中编译器生成的运行时检查
- 2.6.5 栈探测仪
- 2.6.6 栈溢出保护器
- 2.6.7 操作系统策略
- 2.6.8 检测和恢复
- 2.6.9 不可执行栈
- 2.6.10 W^X
- 2.6.11 PaX
- 2.6.12 未来发展方向
- 2.7 著名的漏洞
- 2.7.1 远程登录
- 2.7.2 Kerberos
- 2.8 小结
- 2.9 阅读材料
- 第3章指针诡计
- 3.1 数据位置
- 3.2 函数指针
- 3.3 对象指针
- 3.4 修改指令指针
- 3.5 全局偏移表
- 3.6 dtors区
- 3.7 虚指针
- 3.8 atexit和on-exit函数
- 3.9 longjmp函数
- 3.10 异常处理
- 3.10.1 结构化异常处理
- 3.10.2 系统默认异常处理
- 3.11 缓解策略
- 3.11.1 栈探测仪
- 3.11.2 W-X
- 3.11.3 对函数指针编码和解码
- 3.12 小结
- 3.13 阅读材料
- 第4章动态内存管理
- 4.1 C内存管理
- 4.1.1 C标准内存管理函数
- 4.1.2 对齐
- 4.1.3 alloca和变长数组
- 4.2 常见的C内存管理错误
- 4.2.1 初始化错误
- 4.2.2 未检查返回值
- 4.2.3 Null或无效指针解引用
- 4.2.4 引用已释放内存
- 4.2.5 多次释放内存
- 4.2.6 内存泄漏
- 4.2.7 零长度分配
- 4.2.8 DR # 400
- 4.3 C++的动态内存管理
- 4.3.1 分配函数
- 4.3.2 释放函数
- 4.3.3 垃圾回收
- 4.4 常见的C++内存管理错误
- 4.4.1 未能正确检查分配失败
- 4.4.2 不正确配对的内存管理函数
- 4.4.3 多次释放内存
- 4.4.4 释放函数抛出一个异常
- 4.5 内存管理器
- 4.6 Doug Lea的内存分配器
- 4.7 双重释放漏洞
- 4.7.1 写入已释放的内存
- 4.7.2 RtlHeap
- 4.7.3 缓冲区溢出(终极版)
- 4.8 缓解策略
- 4.8.1 空指针
- 4.8.2 一致的内存管理约定
- 4.8.3 phkmalloc
- 4.8.4 随机化
- 4.8.5 OpenBSD
- 4.8.6 jemalloc内存管理器
- 4.8.7 静态分析
- 4.8.8 运行时分析工具
- 4.9 值得注意的漏洞
- 4.9.1 CVS缓冲区溢出漏洞
- 4.9.2 Microsoft数据访问组件
- 4.9.3 CVS服务器双重释放漏洞
- 4.9.4 MIT Kerberos 5中的漏洞
- 4.10 小结
- 第5章整数安全
- 5.1 整数安全导论
- 5.2 整数数据类型
- 5.2.1 无符号整数类型
- 5.2.2 回绕
- 5.2.3 有符号整数类型
- 5.2.4 有符号整数的取值范围
- 5.2.5 整数溢出
- 5.2.6 字符类型
- 5.2.7 数据模型
- 5.2.8 其他整数类型
- 5.3 整数转换
- 5.3.1 转换整数
- 5.3.2 整数转换级别
- 5.3.3 整数类型提升
- 5.3.4 普通算术转换
- 5.3.5 由无符号整数类型转换
- 5.3.6 由有符号整数类型转换
- 5.3.7 转换的影响
- 5.4 整数操作
- 5.4.1 赋值
- 5.4.2 加法
- 5.4.3 减法
- 5.4.4 乘法
- 5.4.5 除法和求余
- 5.4.6 移位
- 5.5 整数漏洞
- 5.5.1 漏洞
- 5.5.2 回绕
- 5.5.3 转换和截断错误
- 5.5.4 非异常的整数逻辑错误
- 5.6 缓解策略
- 5.6.1 整数类型的选择
- 5.6.2 抽象数据类型
- 5.6.3 任意精度算术
- 5.6.4 范围检查
- 5.6.5 前提条件和后验条件测试
- 5.6.6 安全整数库
- 5.6.7 溢出检测
- 5.6.8 编译器生成的运行时检查
- 5.6.9 可验证范围操作
- 5.6.10 仿佛无限范围整数模型
- 5.6.11 测试与分析
- 5.7 小结
- 第6章格式化输出
- 6.1 变参函数
- 6.2 格式化输出函数
- 6.2.1 格式字符串
- 6.2.2 GCC
- 6.2.3 Visual C++
- 6.3 对格式化输出函数的漏洞利用
- 6.3.1 缓冲区溢出
- 6.3.2 输出流
- 6.3.3 使程序崩溃
- 6.3.4 查看栈内容
- 6.3.5 查看内存内容
- 6.3.6 覆写内存
- 6.3.7 国际化
- 6.3.8 宽字符格式字符串漏洞
- 6.4 栈随机化
- 6.4.1 阻碍栈随机化
- 6.4.2 以双字的格式写地址
- 6.4.3 直接参数访问
- 6.5 缓解策略
- 6.5.1 排除用户输入的格式字符串
- 6.5.2 静态内容的动态使用
- 6.5.3 限制字节写入
- 6.5.4 C11附录K边界检查接口
- 6.5.5 iostream与stdio
- 6.5.6 测试
- 6.5.7 编译器检查
- 6.5.8 静态污点分析
- 6.5.9 调整变参函数的实现
- 6.5.10 Exec Shield
- 6.5.11 FormatGuard
- 6.5.12 静态二进制分析
- 6.6 著名的漏洞
- 6.6.1 华盛顿大学FTP Daemon
- 6.6.2 CDE ToolTalk
- 6.6.3 Ettercap NG-0.7.2版
- 6.7 小结
- 6.8 阅读材料
- 第7章并发
- 7.1 多线程
- 7.2 并行
- 7.2.1 数据并行
- 7.2.2 任务并行
- 7.3 性能目标
- 7.4 常见错误
- 7.4.1 竞争条件
- 7.4.2 损坏的值
- 7.4.3 易变的对象
- 7.5 缓解策略
- 7.5.1 内存模型
- 7.5.2 同步原语
- 7.5.3 线程角色分析(研究)
- 7.5.4 不可变的数据结构
- 7.5.5 并发代码属性
- 7.6 缓解陷阱
- 7.6.1 死锁
- 7.6.2 过早释放锁
- 7.6.3 争用
- 7.6.4 ABA问题
- 7.7 值得注意的漏洞
- 7.7.1 在多核动态随机访问存储器系统中的DoS攻击
- 7.7.2 系统调用包装器中的并发漏洞
- 7.8 小结
- 第8章文件I/O
- 8.1 文件I/O基础
- 8.1.1 文件系统
- 8.1.2 特殊文件
- 8.2 文件I/O接口
- 8.2.1 数据流
- 8.2.2 打开和关闭文件
- 8.2.3 POSIX
- 8.2.4 C++中的文件I/O
- 8.3 访问控制
- 8.3.1 UNIX文件权限
- 8.3.2 进程特权
- 8.3.3 更改特权
- 8.3.4 管理特权
- 8.3.5 管理权限
- 8.4 文件鉴定
- 8.4.1 目录遍历
- 8.4.2 等价错误
- 8.4.3 符号链接
- 8.4.4 规范化
- 8.4.5 硬链接
- 8.4.6 设备文件
- 8.4.7 文件属性
- 8.5 竞争条件
- 8.5.1 检查时间和使用时间
- 8.5.2 创建而不替换
- 8.5.3 独占访问
- 8.5.4 共享目录
- 8.6 缓解策略
- 8.6.1 关闭竞争窗口
- 8.6.2 消除竞争对象
- 8.6.3 控制对竞争对象的访问
- 8.6.4 竞争检测工具
- 8.7 小结
- 第9章推荐的实践
- 9.1 安全开发生命周期
- 9.1.1 TSP-Secure
- 9.1.2 计划和跟踪
- 9.1.3 质量管理
- 9.2 安全培训
- 9.3 要求
- 9.3.1 安全编码标准
- 9.3.2 安全质量需求工程
- 9.3.3 用例/误用例
- 9.4 设计
- 9.4.1 安全的软件开发原则
- 9.4.2 威胁建模
- 9.4.3 分析攻击面
- 9.4.4 现有代码中的漏洞
- 9.4.5 安全包装器
- 9.4.6 输入验证
- 9.4.7 信任边界
- 9.4.8 黑名单
- 9.4.9 白名单
- 9.4.10 测试
- 9.5 实现
- 9.5.1 编译器检查
- 9.5.2 仿佛无限范围整数模型
- 9.5.3 有安全保证的C/C++
- 9.5.4 静态分析
- 9.5.5 源代码分析实验室
- 9.5.6 深层防御
- 9.6 验证
- 9.6.1 静态分析
- 9.6.2 渗透测试
- 9.6.3 模糊测试
- 9.6.4 代码审计
- 9.6.5 开发人员准则与检查清单
- 9.6.6 独立安全审查
- 9.6.7 攻击面回顾
- 9.7 小结
- 9.8 阅读材料
- 参考文献
-
缩略语