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

news/2024/11/15 15:19:21/文章来源:https://www.cnblogs.com/lying7/p/18385055

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. 通常可以在源代码中轻松扫描出使注入攻击成为风险的危险操作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/788929.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第12篇 window上验证mysql是否安装成功

1.命令提示符cmd窗口验证 1.1 键盘win+R打开命令提示符,输入cmd。 1.2 在电脑中找到安装好的MySQL的bin文件目录 。这是我的安装目录C:\Program Files\MySQL\MySQL Server 5.7\bin。1.3 在命令提示符中输入cd C:\Program Files\MySQL\MySQL Server 5.7\bin,再输入mysql -h loc…

南沙csp-j/s陈老师解题:1050:骑车与走路

​【题目描述】在清华校园里,没有自行车,上课办事会很不方便。但实际上。并非去办任何事情都是骑车快,因为骑车总要找车、开锁、停车、锁车等,这要耽误一些时间。假设找到自行车,开锁并骑上自行车的时间为27秒;停车锁车的时间为23秒;步行每秒行走1.2米,骑车每秒行走3.0米…

第11篇 MySql8.0 安装配置教程细讲

话不多说直接开干在安装之前, 先确定一下, 电脑上之前有没有安装MySQL ?或者看看有没有这个路径如果有, 请搜索网上的教程 1,停止服务 2,删除注册表 3,删除安装目录和data目录(如果有data目录的话) 弄完最好再重启系统 如果有删除残留可能导致后面安装出现问题 再开始阅读本教…

记录一次pip安装不了包(换源也不得行)

记录一次pip安装不了包(换源也不得行) 1.使用阿里云。安装不成功 (.venv) PS E:\python项目\路飞学院> pip install scrapy==2.5.1 -i http://mirrors.aliyun.com/pypi/simple/ Looking in indexes: http://mirrors.aliyun.com/pypi/simple/ WARNING: The repository lo…

net core中byte数组如何高效转换为16进制字符串

.NET Core 中把 byte[] 转换为 16 进制字符串的五种方法,简洁,灵活,高性能,哪个适合你?在 .NET Core 中,如何把 byte[] 转换为 16 进制字符串?你能想到哪些方法?什么方式性能最好?今天和大家分享几种转换方式。 往往在处理字符串性能问题时,首先应该想到的是怎么想办…

学习爬虫day30-瑞数eval入口定位及VM

“VM”表示的是Virtual Machine(虚拟机),这些文件通常表示由浏览器生成和执行的虚拟机脚本环境中的临时脚本。这些脚本并不是项目源代码的一部分,也不是实际存在的物理文件。 它们在浏览器的内存中创建并执行;通过eval函数或者new Function方法,Chrome浏览器会创建一个&q…

【待做】【文件包含】PHP伪协议

https://mp.weixin.qq.com/s/sxjf5TppUcjIsfk836BMhA 【文件包含】PHP伪协议原创 菜鸟小新PHP支持的伪协议 file:// — 访问本地文件系统 http:// — 访问 HTTP(s) 网址 ftp:// — 访问 FTP(s) URLs php:// — 访问各个输入/输出流(I/O streams) zlib:// — 压缩流 data:// —…

centos基础设置

1.设置网络 # 配置网络 vi /etc/sysconfig/network-scripts/ifcfg-ens33 #将里面的onboard设置为yes2.修改计算机名 使用命令行: 打开终端。 使用 hostnamectl 命令可以直接修改主机名。例如,如果您想将主机名更改为 mynewhostname,您可以使用以下命令:sudo hostnamectl se…

【图论】【模板】2-SAT

2-SAT 定义 可以看一下洛谷模板题目的定义:思路 每个等式都可以理解为如果 \(x\) 不是条件规定的,那么 \(y\) 必须按照条件规定的,反过来也一样。 所以我们将一个数字拆成两个点,对于每个条件将代表取反 \(x\) 的点与 \(y\) 相连,将代表取反 \(y\) 的点与 \(x\) 相连。 比…

【字符串匹配】KMP

2024-8-28 最后更新时间 2024-8-28 \(\Large\mathcal{1,Recommendation}\) Knuth-Morris-Pratt 字符串查找算法,简称为KMP算法,常用于在一个文本串 S 内查找另一个文本 P 的出现位置,因为时间复杂度优异而被广泛使用。 这个算法由 Donald Knuth、Vaughan Pratt、James H. Mo…

两个月Crypto从入门到进阶专题第1天

绪论: 今天主要讲RSA的原理以及python的实现,RSA的历史这些就不讲了,RSA的历史你自己去搜视频看才有趣,三个大佬创造的RSA。1.RSA加密过程1.1选择p,q两个质数 (为什么选质数,后面就知道了,这里说一下学习方法:有一些步骤不知道为什么的,先看下去,可能后面会给你解答…

Android Qcom USB Driver学习(十一)

基于TI的Firmware Update固件升级的流程分析usb appliction layers的数据 USB Protocol Package①/② map to check password correct Package Format: Byte[0] = Report Id Byte[1] = Valid Length (0x21 = 33) Byte[2] = BSL Core Commands(0x11 RX Password) Byte[3] = Vali…