随着网络的普及,安全问题已经成了软件业的头等大事。但是,软件安全性的加强,仅仅依靠增加安全功能模块是远远不够的,必须从编码阶段就将安全理念牢记在心。本书是第一本指导程序员从内部加强软件安全的著作。由微软公司的两位安全权威撰写。本书从各种程序代码中可能存在的安全漏洞和安全问题入手,通过大量的实例和代码,详细地分析说明了编写安全的应用程序的方方面面,提供了一些目前尚无其他文档可查的用于安全的设计、安全的编码及测试技术的一些实用技术内幕。本书内容翔实,许多实例代码取材于微软实践过的第一手材料,实用性极强。配套光盘除包含大量实例、工具外,还提供了一份包含本书文字内容的完整的可检索的电子版(电子书)。
译者序\r\n序\r\n前言\r\n\r\n第一部分 现代安全\r\n\r\n第1章 对安全系统的需求 \r\n\r\n1.1 “Wild Wild Web”上的应用程序 \r\n1.2 让每个人都参与进来 \r\n1.2.1 利用机智使整个组织认识到安全的重要性 \r\n1.2.2 使用搞破坏的方法 \r\n1.3 用来灌输安全文化的一些思想 \r\n1.3.1 让老板发一封电子邮件 \r\n1.3.2 任命安全宣传员 \r\n\r\n第2章 设计安全的系统 \r\n\r\n2.1 两个常见的安全性错误 \r\n2.2 赖以生存的安全策略 \r\n2.2.1 建立一个安全步骤 \r\n2.2.2 定义产品的安全目标 \r\n2.2.3 将安全性看做是产品的一个功能 \r\n2.2.4 从错误中吸取教训 \r\n2.2.5 使用最小权限 \r\n2.2.6 使用纵深防御 \r\n2.2.7 假设外部系统是不安全的 \r\n2.2.8 做好失效时的计划 \r\n2.2.9 失效时进入安全模式 \r\n2.2.10 选择安全的默认值\r\n2.2.11 请记住安全性功能不等于安全的功能 \r\n2.2.12 不要将安全建立在模糊信息上 \r\n2.2.13 最后三个观点 \r\n2.3 用威胁模型做安全设计 \r\n2.3.1 集体讨论已经知道的对系统的威胁 \r\n2.3.2 以风险递减的顺序给威胁排序 \r\n2.3.3 选择对威胁做何种反应 \r\n2.3.4 选择技术来缓解威胁 \r\n2.4 安全方法 \r\n2.4.1 认证 \r\n2.4.2 授权 \r\n2.4.3 抗篡改和加强保密的方法 \r\n2.4.4 保护秘密,更好的办法是不存储秘密 \r\n2.4.5 加密、散列、MAC和数字签名 \r\n2.4.6 审核 \r\n2.4.7 过滤、扼杀和服务质量 \r\n2.4.8 最小权限 \r\n2.5 回到工资应用程序范例 \r\n2.6 丰富的威胁和解决方案 \r\n\r\n第二部分 安全的编码技术\r\n\r\n第3章 头号公敌:缓冲区溢出 \r\n\r\n3.1 静态缓冲区溢出 \r\n3.2 堆溢出 \r\n3.3 数组索引错误 \r\n3.4 格式化字符串bug \r\n3.5 Unicode和ANSI的缓冲区大小不匹配 \r\n3.6 防止缓冲区溢出 \r\n3.7 好消息 \r\n\r\n第4章 确定有效的访问控制 \r\n\r\n4.1 ACL为什么如此重要 \r\n4.2 ACL由哪些部分组成 \r\n4.3 选择一种有效的ACL方法 \r\n4.4 创建ACL\r\n4.4.1 在Windows NT 4中创建ACL\r\n4.4.2 在Windows 2000中创建ACL \r\n4.4.3 使用活动模板库创建ACL \r\n4.5 空的DACL以及其他危险的ACE类型 \r\n4.5.1 空的DACL及审核\r\n4.5.2 危险的ACE类型\r\n4.5.3 如果不能改变空DACL的话应该怎么办\r\n4.6 其他访问控制机制\r\n4.6.1 IP限制\r\n4.6.2 COM+角色\r\n4.6.3 SQL Server触发器和权限\r\n4.6.4 一个医疗上的实例\r\n4.6.5 关于访问控制机制的一点重要说明 \r\n\r\n第5章 使用最低权限运行\r\n\r\n5.1 在实际中的最低权限\r\n5.1.1 病毒和木马\r\n5.1.2 破坏Web服务\r\n5.2 访问控制概述\r\n5.3 权限概述\r\n5.3.1 SeBackupPrivilege问题\r\n5.3.2 SeDebugPrivilege问题\r\n5.3.3 SeTcbPrivilege问题\r\n5.3.4 SeAssignPrimaryTokenPrivilege和SeIncreaseQuotaPrivilege问题\r\n5.4 对令牌的简短回顾\r\n5.5 令牌、权限、SID、ACL以及相关进程\r\n5.6 确定使用恰当权限的过程 \r\n5.6.1 步骤1:找出应用程序所使用的资源 \r\n5.6.2 步骤2:找出应用程序所使用的有特权的API \r\n5.6.3 步骤3:需要哪个账号\r\n5.6.4 步骤4:获取令牌的内容\r\n5.6.5 步骤5:是否所有的SID和权限都需要 \r\n5.6.6 步骤6:调整令牌 \r\n5.6.7 何时使用限定令牌 \r\n5.7 Windows XP和Windows.NET Server中的低权限服务账号 \r\n5.8 调试的最低权限问题 \r\n5.8.1 为什么以普通用户运行的程序会失败 \r\n5.8.2 如何确定为什么程序会失败 \r\n\r\n第6章 密码的缺陷 \r\n\r\n6.1 使用拙劣的随机数 \r\n6.1.1 问题:rand函数 \r\n6.1.2 一种补救方法:CryptGenRandom \r\n6.2 用口令衍生出加密密钥 \r\n6.3 糟糕的密钥管理 \r\n6.4 使用你自己的加密函数 \r\n6.5 使用相同的流密码对密钥加密 \r\n6.5.1 人们为什么要用流密码 \r\n6.5.2 流密码的缺陷 \r\n6.5.3 你“非要”使用相同的密钥会怎么样 \r\n6.6 对流密码的位替换攻击 \r\n6.6.1 解决位替换攻击问题 \r\n6.6.2 什么时候使用散列、密钥散列或数字签名 \r\n6.7 对明文和密文使用同一个缓冲区 \r\n\r\n第7章 涉密信息的存储 \r\n\r\n7.1 攻击方法 \r\n7.2 有时你并不需要存储秘密信息 \r\n7.3 从用户获取秘密信息 \r\n7.4 在Windows 2000和Windows XP中存储秘密信息 \r\n7.5 在Windows NT 4中存储秘密信息 \r\n7.6 在Windows 95、Windows 98、Windows Me和Windows CE中存储秘密信息 \r\n7.7 提高安全限制 \r\n7.7.1 在FAT文件系统的文件中存储数据 \r\n7.7.2 利用一个嵌入密钥和XOR来加数据 \r\n7.7.3 利用嵌入密钥和3DES加密数据 \r\n7.7.4 利用3DES加密数据并在注册表中存储口令 \r\n7.7.5 利用3DES加密数据并在注册表中存储一个强密钥 \r\n7.7.6 利用3DES加密数据、在注册表中存储一个强密钥并对注册表密钥和文件进行ACL处理 \r\n7.8 一个想法:用外部设备对秘密数据加密 \r\n7.8.1 一个应用PPCKey的例子 \r\n7.8.2 PPCKey威胁方式 \r\n\r\n第8章 规范的表示问题 \r\n\r\n8.1 什么是规范?为什么它存在问题 \r\n8.2 一点历史 \r\n8.2.1 绕过AOL的家长控制 \r\n8.2.2 绕过Napster的名称过滤 \r\n8.2.3 绕过eEye的安全检测 \r\n8.2.4 苹果机Mac OS X和Apache中的漏洞 \r\n8.2.5 区域和IE4的“Dotless-IP Address”缺陷 \r\n8.2.6 IIS4的::$DATA漏洞 \r\n8.2.7 DOS驱动名漏洞 \r\n8.2.8 Sun 公司StarOffice /tmp目录符号连接漏洞 \r\n8.3 一般的Windows规范化错误 \r\n8.3.1 长文件名的8.3格式表示方式 \r\n8.3.2 NTFS的另一种数据流 \r\n8.3.3 后缀字符 \r\n8.3.4 \\?\格式 \r\n8.3.5 目录遍历和使用父路径(..) \r\n8.3.6 绝对和相对文件名 \r\n8.3.7 不区分大小写的文件名 \r\n8.3.8 设备名称和保留名称 \r\n8.3.9 UNC共享 \r\n8.4 防止规范化错误的出现 \r\n8.4.1 不要根据名称来做出判断 \r\n8.4.2 使用正则表达式来限制名称的权限 \r\n8.4.3 尝试对名字进行规范化 \r\n8.5 最后的思考:基于非文件的规范化问题 \r\n8.5.1 服务器名 \r\n8.5.2 用户名 \r\n\r\n第三部分 基于网络的应用程序\r\n\r\n第9章 Socket安全 \r\n\r\n9.1 避免服务器被截听 \r\n9.2 选择服务器接口 \r\n9.3 接受连接 \r\n9.4 编写防火墙友好的应用程序 \r\n9.4.1 用一个连接工作 \r\n9.4.2 不要要求服务器连接回客户端 \r\n9.4.3 使用基于连接的协议 \r\n9.4.4 不要通过另外一个协议使你的应用程序进行多路复用 \r\n9.4.5 不要在应用层数据中嵌入主机IP地址 \r\n9.4.6 让你的应用程序可配置 \r\n9.5 欺骗、基于主机和基于端口的信任 \r\n\r\n第10章 RPC、ActiveX控件和DCOM安全 \r\n\r\n10.1 RPC入门 \r\n10.1.1 什么是RPC \r\n10.1.2 创建RPC应用程序 \r\n10.1.3 RPC应用程序的通信原理 \r\n10.2 RPC安全最佳实践 \r\n10.2.1 使用/robust MIDL开关参数 \r\n10.2.2 使用[range]表征项 \r\n10.2.3 要求对连接进行验证 \r\n10.2.4 使用数据包的保密性和完整性 \r\n10.2.5 使用严格的上下文句柄 \r\n10.2.6 不要依靠上下文句柄来进行访问检查 \r\n10.2.7 注意空的上下文句柄 \r\n10.2.8 不要信任你的对端 \r\n10.2.9 使用安全回调 \r\n10.2.10 在单一进程中牵连多个RPC服务器 \r\n10.2.11 考虑为你的终端添加一个注释 \r\n10.2.12 使用主流的协议 \r\n10.3 DCOM安全最佳实践 \r\n10.3.1 DCOM基础 \r\n10.3.2 应用层的安全 \r\n10.3.3 DCOM用户上下文环境 \r\n10.3.4 可编程实现的安全性 \r\n10.3.5 源端和接收端 \r\n10.4 ActiveX入门 \r\n10.5 ActiveX安全最佳实践 \r\n10.5.1 什么样的ActiveX组件是可以安全用于初始化和脚本的 \r\n10.5.2 可安全用于初始化和脚本的最佳实践 \r\n\r\n第11章 拒绝服务(DoS)攻击的防范 \r\n\r\n11.1 应用程序失败攻击 \r\n11.2 CPU资源不足攻击 \r\n11.3 内存资源不足攻击 \r\n11.4 资源不足攻击 \r\n11.5 网络带宽攻击 \r\n\r\n第12章 基于Web服务的安全 \r\n\r\n12.1 永远不要相信用户的输入 \r\n12.1.1 用户输入问题上的安全漏洞 \r\n12.1.2 解决用户输入问题的方法 \r\n12.2位Web特有的规范化问题 \r\n12.2.1 7位和8位ASCII码 \r\n12.2.2 十六进制转换码 \r\n12.2.3 UTF-8可变宽编码 \r\n12.2.4 UCS-2 Unicode编码 \r\n12.2.5 双重编码 \r\n12.2.6 HTML转换码 \r\n12.2.7 对基于Web的标准化问题的解决办法 \r\n12.3 其他基于Web的安全性主题 \r\n12.3.1 HTTP信任问题 \r\n12.3.2 ISAPI程序和过滤器 \r\n12.3.3 不要在Web页中存储涉密数据 \r\n12.3.4 真的需要使用sa吗?可能不是 \r\n\r\n第四部分 特殊话题\r\n\r\n第13章 编写安全的.NET代码 \r\n\r\n13.1 缓冲区溢出和CLR \r\n13.1.1 添加属于你自己的安全性错误处理 \r\n13.1.2 一个事实 \r\n13.2 在.NET中保存涉密数据 \r\n13.3 总是要求适当的权限 \r\n13.4 过度使用Assert \r\n13.5 关于Demand和Assert的其他信息 \r\n13.6 不要害怕拒绝权限 \r\n13.7 对来自不可信任源的数据进行验证 \r\n13.8 ASP.NET中的线程支持问题 \r\n13.9 在部署ASP.NET应用程序之前要禁用跟踪和调试 \r\n13.10 使用.NET Framework产生良好的随机数 \r\n13.11 对来自不可信任源的数据进行反串行化 \r\n13.12 在出现故障时,不要让攻击者获知太多的信息 \r\n13.13 权衡SAOP \r\n13.14 最后的一些想法 \r\n\r\n第14章 测试应用程序的安全性 \r\n\r\n14.1 安全测试员的作用 \r\n14.2 安全性测试与一般测试的区别 \r\n14.3 进入正题 \r\n14.4 建立安全性测试计划 \r\n14.4.1 分解应用程序 \r\n14.4.2 确定组件接口 \r\n14.4.3 依照隐患的相对大小对接口进行排序 \r\n14.4.4 确定每一个接口使用的数据 \r\n14.4.5 通过注入错误的数据发现安全问题 \r\n14.4.6 在测试之前 \r\n14.4.7 制作用于发现缺陷的工具 \r\n14.5 用欺诈性的服务程序测试客户软件 \r\n14.6 用户会看到或修改那些数据吗 \r\n14.7 用安全模板做测试 \r\n14.8 测试代码应该有很高的质量 \r\n14.9 测试端到端的解决方案 \r\n14.10 一些题外话:代码评审 \r\n\r\n第15章 安全的软件安装 \r\n\r\n15.1 最低权限原则\r\n15.2 使用安全配置编辑器 \r\n15.3 低层的安全API \r\n\r\n第16章 常用的好经验 \r\n\r\n16.1 保护客户的隐私 \r\n16.1.1 收集用户数据的类型 \r\n16.1.2 收集用户数据 \r\n16.2 不要告诉攻击者任何东西 \r\n16.3 双重检查你的错误路径 \r\n16.4 让它保持关闭 \r\n16.5 核心模式(Kernel-Mode)错误 \r\n16.5.1 使用用户模式(User-Mode)的内存 \r\n16.5.2 通过未受保护的IOCTL访问有特权的接口 \r\n16.6 考虑给代码添加安全注释 \r\n16.7 借助于操作系统的功能 \r\n16.8 不要依靠用户来做出好的设计 \r\n16.9 安全地调用CreateProcess \r\n16.9.1 不要将lpApplicationName设置为NULL \r\n16.9.2 在lpCommandLine参数中用引号包含执行文件的路径 \r\n16.10 不要创建共享的/可写的段(Segment) \r\n16.11 正确地使用假冒函数 \r\n16.12 不要在\Program Files目录中写用户文件 \r\n16.13 不要在HKLM中写用户数据 \r\n16.14 不要以完全控制或所有访问的方式打开对象 \r\n16.15 对象创建错误 \r\n16.16 安全地创建临时文件 \r\n16.17 客户端安全是一个矛盾 \r\n16.18 例子是模板 \r\n16.19 把你的应用程序的使用者当成傻瓜 \r\n16.20 如果…你将其归功于你的用户 \r\n16.21 判断基于管理员SID的访问 \r\n16.22 允许使用长的口令 \r\n\r\n附 录\r\n\r\n附录A 危险的API \r\n附录B 十条安全法则 \r\n附录C 安全管理员的十条法则 \r\n附录D 安全的误区