读软件开发安全之道:概念、设计与实行12不受信任的输入 ...

打印 上一主题 下一主题

主题 867|帖子 867|积分 2601


1. 不受信任的输入

1.1. 不受信任的输入大概是编写安全代码的开发职员最关心的问题

  • 1.1.1. 最好将其明白为输入系统中的所有不受信任的输入
  • 1.1.2. 来自受信任的代码的输入可以提供格式准确的数据
1.2. 不受信任的输入是指那些不受你控制,并且大概被篡改的数据,包括所有进入系统但你不完全信任的数据

  • 1.2.1. 是你不应该信任的输入,而不是你错信了的输入
1.3. 任何来自外部并进入系统的数据都最好被认为是不受信任的

  • 1.3.1. 不受信任的输入令人担忧,由于它们代表了一种攻击向量,一种能够进入系统并制造麻烦的途径
1.4. 环球最大的不可信输入来源无疑是互联网

  • 1.4.1. 由于软件很难完全断开与互联网的连接,互联网险些对所有系统都构成严重的威胁
2. 输入验证

2.1. 输入验证(或输入消毒)是一种防御性代码,它会对输入的内容施加限制,强制其服从相应的规则

  • 2.1.1. 输入验证是一种很好的防御措施,由于它会将不受信任的输入缩减到应用程序可以安全处理的取值范围内
2.2. 不受信任的输入通常会穿越系统,并向下延伸到多个受信任的组件中

  • 2.2.1. 仅仅凭借你的代码会从受信任的代码中直接调用,并不能包管这些输入是可信的
2.3. 输入验证的基本工作是确保不受信任的输入能够符合设计规范,以便卑鄙代码能处理格式准确的数据
2.4. 我们编写的险些所有代码都只能在一个特定的限制内正常工作,它不能被用于极端情况
2.5. 缓解这种伤害的一种简单方法就是对输入施加人为的限制,清除所有有问题的输入

  • 2.5.1. 限制当然不应该拒绝那些应该获得准确处理的输入
  • 2.5.2. 应该尽快对不受信任的输入举行验证,以便能够最大程度地低落不受约束的输入流向卑鄙代码的风险
  • 2.5.3. 将输入验证视为应对不受信任的输入(特别是攻击面上的输入)的防御机制,但这并不意味着忽视其他的所有输入
2.6. 关键是一致性,因此一个好的模式是在负责处理传入数据的第一层代码中执行输入验证,然后将有效的输入交给更深层的业务逻辑,这些业务逻辑可以自信地认为所有输入都是有效的
2.7. 宁可在冗余的输入验证上犯错,也不要面临产生微小漏洞的风险

  • 2.7.1. 假如你不确定传入的数据是否经过了可靠验证,那么你需要自己执行输入验证来确保安全
3. 确定有效性

3.1. 输入验证一开始要确定什么是有效的

  • 3.1.1. 相当于猜测未来所有有效的输入值,并找出合适的理由来禁止其余的输入值
3.2. 一旦指定了有效值的范围,就很容易确定适合代码的数据范例

  • 3.2.1. 通常有效的做法是对输入建立一个明确的限制,然后在实现中留出充足的余量,来确保准确地处理所有有效输入
  • 3.2.2. 余量是指当你要将一个文本字符串复制到4096字节的缓冲区中时,要将最大的有效长度设置为4000字节,这样你就有了一些余量
  • 3.2.3. 在C语言中,额外的空终止符导致缓冲区溢出1个字符是一个很容易犯的典型错误
4. 验证标准

4.1. 大多数的输入验证查抄都包含几个标准,其中包括确保输入不会超过最大限制、数据以准确的格式传入,并且数据值在一个可接受的范围内
4.2. 查抄值的大小是一种快速测试,主要是为了避免你的代码遭受DoS威胁,DoS威胁会导致你的应用程序在接受数兆字节的不受信任的输入后,变得运行缓慢甚至瓦解
4.3. 步调

  • 4.3.1. 首先限制大小,这样你就不会浪费时间来尝试处理过大的输入
  • 4.3.2. 然后在解析之前确保输入的格式是准确的
  • 4.3.3. 最后查抄效果值是否在可接受的范围内
4.4. 确定值的有效范围大概是最主观的选择,但紧张的是要有具体的限制

  • 4.4.1. 范围的定义取决于数据范例
  • 4.4.2. 以字符而不是字节为单位指定字符串的最大长度,这样平常人才可以明白这个约束条件的寄义
4.5. 根据某个目的来思量输入的有效性会很有资助
4.6. 选择一个对用户更友爱的限制会更有意义
4.7. 输入验证的主要目的是确保无效输入不会通过验证

  • 4.7.1. 最简单的做法是拒绝无效输入
  • 4.7.2. 更宽容的选择是检测无效输入并将其修改为有效的形式
5. 拒绝无效输入

5.1. 拒绝不符合特定规则的输入,是最简单并且可以说是最安全的做法
5.2. 完全接受或拒绝是最干净妥当的做法,并且通常最容易做对
5.3. 每当人们直接提供输入(好比填写Web表格)时,最好能够提供充足的关于错误的信息,使他们能够更轻松地纠正错误并重新提交

  • 5.3.1. 暂停下来并要求数据源提供有效的输入,这是举行输入验证的保守做法,它也为平常用户提供了学习温顺应的机会
5.4. 最佳实践

  • 5.4.1. 解释有效输入的构成,至少让阅读的人不必猜测并重试
  • 5.4.2. 一次标志多个错误,以便用户能够一次性更正并重新提交
  • 5.4.3. 当需要人们直接输入时,保持规则简单明了
  • 5.4.4. 将复杂的表格分成几个部分,并且每个部分都有一个单独的表格,这样人们可以看到事变的进展
5.5. 最佳方法是编写文档,准确地描述预期的输入格式和其他约束
5.6. 在专业运行系统的输入验证中,会完全拒绝整批输入,而不是尝试处理部分有效的数据子集,这种做法大概最公道,由于验证不通过就表示有些输入不符合规范

  • 5.6.1. 这样做允许纠正错误并再次提交完整的数据集,而无须梳理出哪些已处理,哪些未处理
6. 纠正无效输入

6.1. 完全接受有效输入并拒绝其他输入,这种做法既安全又简单,但绝对不是最好的做法
6.2. 假如我们不希望由于微小的错误而阻止人们继续的话,可以通过输入验证代码来尝试更正那些无效的输入,将它们转换为有效值,而不是直接拒绝输入
6.3. 根据用户的输入,以官方格式提供猜测出的相似地址,以供用户选择
6.4. 对于难度较高的验证需求来说,最好的办法是将输入设计得尽大概简单
6.5. 适当的输入验证需要谨慎的判定,但它也使软件系统更可靠、更安全
7. 字符串漏洞

7.1. 长度问题

  • 7.1.1. 长度是第一个挑战,由于字符串大概是无限长的
  • 7.1.2. 第一道防线是将不受信任的输入字符串的长度限制在公道的范围内
  • 7.1.3. 在分配缓冲区时,不要将字符数与字节长度混淆
7.2. Unicode问题

  • 7.2.1. Unicode是一个丰富的字符集,但这种丰富性的代价是隐藏的复杂性,并且这些复杂性会成为漏洞使用的沃土
  • 7.2.2. 大量字符编码可以将全世界的文本表示为字节,但大多数软件会将Unicode作为一种通用语
  • 7.2.2.1. Unicode标准(版本13.0)的长度刚超过1000页,指定了超过14万个字符、规范化算法、旧字符代码标准的兼容性,以及双向语言支持
  • 7.2.2.2. 险些涵盖了世界上所有的书面语言,其编码超过了100万个代码点
  • 7.2.2.3. UTF-8是最常见的编码,同时还有UTF-7、UTF-16和UTF-32编码
  • 7.2.3. 排序规则(collation)取决于编码和语言,假如不关注它的话,就会产生意想不到的效果
  • 7.2.4. 在不需要支持差别的语言环境时,请思量明确指定其运行的语言环境,而不是继续系统配置中的设置
  • 7.2.5. 安全性的底线是使用受信任的库来处理字符串,而不是直接对字节举行处理
  • 7.2.6. Unicode是对字符而不是字形(以何种视觉形式来出现字符)举行编码
  • 7.2.7. 规范化文本的一种常用方法是将字符串中的字母转换为大写或小写
8. 注入攻击漏洞

8.1. 一种常见的软件技术能够构造一个字符串或数据结构(其中编码了要执行的操作)​,然后执行该字符串或数据结构来完成指定的任务
8.2. 假如攻击者可以改变操作的预期效果,那么这种影响大概会穿越信任边界,并由具有更高权限的软件执行

  • 8.2.1. 这就是对注入攻击的解释
8.3. 包括但不限于

  • 8.3.1. SQL语句
  • 8.3.1.1. SQL注入攻击
  • 8.3.2. 文件路径名称
  • 8.3.3. 正则表达式(作为一种DoS威胁)​
  • 8.3.4. XML数据(尤其是XXE声明)​
  • 8.3.5. shell命令
  • 8.3.6. 将字符串解释为代码(好比JavaScript的eval函数)​
  • 8.3.7. HTML和HTTP头部
8.4. 路径遍历

  • 8.4.1. 文件路径遍历是一个与注入攻击密切相关的常见漏洞
  • 8.4.2. 这种攻击不会破坏成对的引号​,而是会进入父目次,以获得对文件系统其他部分的不测访问
  • 8.4.3. 预防这类攻击最好的方法是对允许输入的字符集举行限制
  • 8.4.3.1. 仅由字母和数字构成的字符串就足以修复这个漏洞
  • 8.4.3.2. 它清除了从文件系统预期部分“逃逸”出去所需要的文件分隔符和父目次形式
  • 8.4.3.3. 只提供对于某个目次或其子目次中文件的访问,但绝对不提供对其他位置文件的访问
  • 8.4.3.4. base目次是一个可靠的路径,由于它不会涉及任何不受信任的输入:它的输入完全来自程序员控制下的值
8.5. 正则表达式

  • 8.5.1. 正则表达式(regex)具有高效、机动和易于使用的特点,它提供了非常广泛的功能,并且大概是最常用来解析文本字符串的通用工具
  • 8.5.2. 在编码和执行上,正则表达式通常比暂时代码更快且更可靠
  • 8.5.3. 正则表达式库会编译出状态表,状态表是一个解释器(有限状态机或类似的自动机制)​,能够执行字符串的匹配
  • 8.5.4. 缓解问题的最佳方法取决于具体的计算,但有几种通用的方法可以用来应对这些攻击
  • 8.5.4.1. 要避免让不受信任的输入影响到有大概瓦解的计算
  • 8.5.4.2. 在使用正则表达式的情况下,不要让不受信任的输入来定义正则表达式,尽大概避免回溯,并且限制使用正则表达式匹配的字符串的长度
  • 8.5.4.3. 要思量最糟糕的计算,然后对其举行测试,以确保不会执行得过慢
8.6. XML的伤害

  • 8.6.1. XML是表示结构化数据的最盛行的方法之一,由于它功能强大且易于阅读
  • 8.6.2. 将不受信任的输入清除在你的代码所处理的任何XML之外
  • 8.6.3. 假如你不需要XML外部实体,就可以通过在输入中清除不受信任的输入,或者禁止处理这类声明来防止这类攻击
9. 缓解注入攻击

9.1. 输入验证始终是很好的第一道防线,但思量到允许的输入中会包含的内容,仅此一项缓解措施不一定充足
9.2. 作为额外的防御层,要研究会形成的命令或语句的语法,并且要确保应用了所有必要的引用或转义,以确保不会堕落
9.3. 通常可以在源代码中轻松扫描出使注入攻击成为风险的伤害操作

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

欢乐狗

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表