安全应用程序架构基础:分离、配置和访问
如今,软件开发者被鼓励专注于构建,这是一件很棒的事情。我们受益于创客文化、“永不停歇”的态度、开源协作,以及一系列帮助我们确定优先级并以最高效率执行的应用程序。我们处在一个持续创造的环境中,无论是团队还是个人创业者,都能最大限度地提高生产力。
有时,这种极快的生产力也会显示出其缺点。
随着我对安全最佳实践的了解越来越多,我忍不住发现越来越多的应用程序对安全一无所知。缺乏安全意识似乎导致那些与产品发布没有直接关系的任务缺乏优先级。市场似乎更加重视发布一款可用的产品,而不是安全的产品,普遍的态度是“安全问题以后再说”。
拼凑一个更多地基于权宜之计而不是长远考虑的基础是构建应用程序的糟糕方式,也是积累安全债务的好方法。安全债务与技术债务类似,是通过做出(通常是草率的)决策而积累的,这些决策可能会使以后保护应用程序的安全变得更加困难。如果您熟悉“向左推”的概念(或者如果您阅读了我关于敏感数据泄露的文章),您就会知道,当涉及到安全性时,有时没有一个“以后”的版本为时已晚。这是一种遗憾,尤其是在开发过程早期遵循一些具有高收益的基本安全实践并不比不遵循它们花费更多时间的情况下。通常,这取决于拥有一些基本但重要的知识,这些知识使您可以做出更安全的决策。
虽然应用程序架构千差万别,但有一些基本原则是可以通用的。本文将对一些领域进行高阶概述,希望能为开发人员指明正确的方向。
我们称之为应用程序“架构”肯定是有原因的,我认为这是因为软件架构在某些基本方面与建筑物的架构相似。(或者至少,以我完全没有建筑创作经验的水平,我想象中的一座非常实用的建筑是这样的。)以下是构建安全应用程序架构的三个基本要点:
- 独立存储
- 定制配置
- 控制访问和用户范围
这只是一个起点,旨在让我们从正确的方向开始;一个完全实现的应用程序的安全态势的完整图景包括超出本文范围的领域,包括身份验证、日志记录和监控、集成,有时还包括合规性。
1. 分开存储
从安全角度来看,“隔离”的概念是指将不同用途的文件存储在不同的地方。我们在建造大楼并决定所有房间的布局时,通常会将大厅设在一楼,将行政办公室设在较高的楼层,例如远离主干道的地方。虽然两者都是房间,但我们知道它们的用途不同,功能需求也不同,安全要求也可能大相径庭。
当谈到我们的文件时,如果我们考虑一个简单的文件结构,我们可能最容易理解其好处:
application/
├───html/
│ └───index.html
├───assets/
│ ├───images/
│ │ ├───rainbows.jpg
│ │ └───unicorns.jpg
│ └───style.css
└───super-secret-configurations/
└───master-keys.txt
在我们的简化示例中,假设我们应用程序的所有图片都存储在该application/assets/images/
目录中。当我们的某个用户创建个人资料并上传图片时,这张图片也会存储在这个文件夹中。这很合理,对吧?毕竟这是一张图片,图片就存放在这里。那么问题是什么呢?
如果您熟悉在终端中浏览文件结构,您可能之前见过这种语法:../../
。 这两个点是表示“上一级目录”的便捷方式。如果我们在上面的简单文件结构的目录cd ../../
中执行命令images/
,我们将进入assets/
,然后再回到根目录。 这是一个问题,因为存在一个被称为路径遍历application/
的小漏洞。
点语法不仅节省了我们一些输入,还带来了一个有趣的优势:我们实际上不需要知道父目录的名称就可以访问它。设想一个攻击载荷脚本,images/
它被传递到我们不安全的应用程序的文件夹中,然后使用命令向上一级目录前进cd ../
,然后将找到的所有内容发送给攻击者,如此反复。最终,它会到达应用程序的根目录并访问该super-secret-configurations/
文件夹。这可不是什么好事。
虽然当然应该采取其他措施来防止路径遍历和相关的用户上传漏洞,但迄今为止最简单的预防措施是存储分离。核心应用程序文件和资产不应与其他数据(尤其是用户输入)混合。最好将用户上传的文件以及活动日志(可能包含重要数据,容易受到注入攻击)与主应用程序分开存放。
可以通过几种方式实现分离,例如使用不同的服务器、不同的实例、不同的 IP 范围或不同的域。
2. 定制配置
虽然在某些情况下,为了快速开发而花费时间进行定制可能会被人诟病,但我们绝对希望定制的一个方面是配置设置。安全配置错误被列入 OWASP 十大安全隐患之一,因为大量安全事件的发生都是因为服务器、防火墙或管理帐户在生产环境中使用默认设置运行。希望新大楼启用后,我们会更加小心,确保没有把钥匙留在锁里。
通常,与默认设置相关的攻击的受害者并非专门针对的。相反,攻击者会通过自动扫描工具发现这些受害者,这些工具会在许多可能的目标上运行,有效地探测许多不同的系统,看看是否有任何系统会翻转并暴露一些有用的漏洞。这种攻击的自动化特性意味着我们必须仔细检查架构中每个部分的设置。即使某个部分看起来并不重要,也可能存在漏洞,使攻击者能够利用它作为入侵我们更大型应用程序的门户。
特别地,检查无人值守区域的架构组件,例如:
- 默认帐户(尤其是使用默认密码的帐户)仍在使用;
- 示例网页、教程应用程序或应用程序中留下的示例数据;
- 不必要的端口仍在服务中,或向互联网开放的端口;
- 不受限制的允许 HTTP 方法;
- 自动日志中存储的敏感信息;
- 托管服务中的默认配置权限;以及
- 目录列表或敏感文件类型默认可访问。
此列表并非详尽无遗,特定架构组件(例如云存储或 Web 服务器)会具有其他可配置的功能,因此应进行检查。通常,我们可以通过精简架构组件来减少应用程序的攻击面。如果我们使用更少的组件或不安装不必要的模块,那么需要配置和保护的潜在攻击入口点就会更少。
3. 控制访问和用户范围
在应用程序中,最难测试的安全问题之一是访问控制配置不当。自动化测试工具的能力有限,无法找到应用程序中某个用户无法访问的区域,因此通常只能通过手动测试或源代码审查来发现。通过在软件开发生命周期的早期阶段,在制定架构决策时考虑这一漏洞,我们可以降低它演变成日后难以修复的问题的风险。毕竟,我们不会简单地把万能钥匙放在高高的窗台上,然后祈祷没人带着梯子过来。
OWASP Top 10 列出了访问控制失效的情况,并对其各种表现形式进行了更详细的说明。举一个简单的例子,假设一个应用程序有两个访问权限级别:管理员和用户。我们可能会为应用程序构建一个功能,例如审核或禁止用户,并设定只有管理员才能使用。如果我们意识到访问控制配置错误或漏洞利用的可能性,我们可能会决定将审核功能构建在与用户可访问空间完全隔离的区域,例如在不同的域中,或者作为用户不共享的模型的一部分。这大大降低了访问控制配置错误或特权提升漏洞可能导致用户日后不当访问审核功能的风险。
当然,在我们的应用程序中,强大的访问控制需要进一步的支持才能有效,我们应该考虑诸如作为 URL 参数传递的敏感令牌或密钥,或者控制是否安全失败等因素。尽管如此,通过在架构阶段考虑授权,我们可以使进一步的增强更容易实现。
实现利益最大化的安全基础知识
就像选择经过严格审查的框架可以避免累积技术债务一样,开发人员可以通过了解常见漏洞以及我们可以做出的简单架构决策来缓解这些漏洞,从而避免安全债务。想要更详细地了解如何从一开始就将安全性融入应用程序,OWASP 应用程序安全验证标准是一个可靠的指南。
文章来源:https://dev.to/victoria/secure-application-architecture-basics-separation-configuration-and-access-28a7