在开源应用程序上禁用详细的异常页面有什么用?

信息安全 Web应用程序 脆弱性 开源 朦胧 调试
2021-08-21 13:48:53

Web 应用程序的框架通常可以在生产模式或开发模式下运行。两种模式之间的主要区别之一是如何处理异常:在开发模式下,通常会向浏览器发送带有堆栈跟踪的详细异常信息,而生产模式只会提供一个通用的(尽管可定制的)错误页面,该页面没有的任何更详细的信息。

出于这个原因,框架的文档通常也会警告不要在生产中使用开发模式;这是 .NET Core 的一个示例:

警告仅当应用程序在开发环境中运行时才启用开发者异常页面当应用程序在生产中运行时,您不希望公开共享详细的异常信息。

这是来自 Django 文档的类似警告

DEBUG切勿在打开的情况下将站点部署到生产环境中。

调试模式的主要功能之一是显示详细的错误页面。DEBUG如果您的应用在is时引发异常True,Django 将显示详细的回溯,包括很多关于您的环境的元数据,例如所有当前定义的 Django 设置(来自settings.py)。

我无法理解上述安全措施背后的原因?

如果我理解,推理是这样的:详细的错误页面将允许潜在的攻击者发现有关应用程序源代码的详细信息 = 他们可能会发现弱点 = 不好。这不是通过默默无闻来定义安全吗?

另外:如果应用是开源的,这些措施有什么用?禁用详细的异常页面应该是为了防止攻击者找到有关其源代码的详细信息,但这些 - 按照设计- 存在于公共 GitHub 存储库中。似乎在这种情况下,我还不如在开发模式下运行应用程序,至少如果用户发现有意外错误,他们将能够给我更详细的信息,这可能有助于我修复这个错误?

如果我上面引用的文档警告背后的推理是正确的,那么这对我来说意味着开发开源 webapps 本身就是一个安全漏洞!因为如果允许攻击者找到源代码的一些细节是一件大事,那么简单地将源代码提供给任何感兴趣的人该有多糟糕!然而,AFAIK,开源并不被认为是一种无效且本质上不安全的模型。

我在这里想念什么?为什么要禁用详细的异常页面?

4个回答

它可以向攻击者透露实现的细节,从而可以发起更好的攻击。引用 O WASP 页面关于不正确的错误处理

即使错误消息没有提供很多细节,这些消息中的不一致仍然可以揭示有关站点如何工作的重要线索,以及隐藏的信息。例如,当用户尝试访问不存在的文件时,错误消息通常会指示“找不到文件”。当访问一个用户没有被授权的文件时,它会显示“访问被拒绝”。用户不应该知道该文件甚至存在,但是这种不一致很容易揭示出不可访问文件的存在或不存在或站点的目录结构。

启用调试模式时需要考虑几件事。

  1. 信息泄露:框架版本号、配置值、API 密钥。Django 有一些基本的保护措施来清除其异常页面中看起来敏感的设置值,但您不应该依赖此功能。

  2. 内存泄漏:一些框架将扩展的调试信息保存在内存中,以允许对请求进行事后自省。这导致本质上是内存泄漏,攻击者可能会使用它来使 web 应用程序崩溃。例如,当 DEBUG=True 时Django ORM 存储曾经在连接上完成的所有 SQL 查询

  3. 远程代码执行:一些调试框架允许您执行服务器端代码以在异常发生后内省堆栈中的对象。例如,Werkzeug 调试器

  4. 性能:收集这些调试信息可能会导致性能显着下降。我有一些在生产模式下运行不到一秒的 Django 视图,如果你使用 django-debug-toolbar 打开 SQL 日志记录和调试模式,这需要将近一分钟。

所有这些都有一个共同点,即面向调试的功能通常设计用于 localhost 环境,其中安全性从来都不是真正的问题。

举一个您引用的示例,即currently defined Django settings您为站点设置的值平均值。这些设置存在的事实并不是秘密。您给他们的值(如管理员列表)可能是。

我认为您的误解在于以下推理:

详细的错误页面将允许潜在的攻击者发现有关应用程序源代码的详细信息

真正的问题是详细的错误页面将允许潜在的攻击者发现有关应用程序当前配置的详细信息。

另一个问题是攻击者如何找到有关应用程序源代码的详细信息(例如,哪个应用程序正在运行该应用程序的哪个版本,例如查看是否正在使用更旧、更易受攻击的版本)。是的,详细的错误页面会对此有所帮助,但也有其他方法可以做到这一点。

另外,我要指出,隐藏软件的源代码(即闭源软件)本身就是“通过默默无闻的安全性”。

这样做只是一个好习惯,以避免向攻击者泄露敏感信息或任何有用的提示。向其他人显示调试信息并不是一个真正的漏洞,但无论如何它都可以被视为一个弱点。换句话说,您的调试信息可能会或可能不会向攻击者显示任何有趣的内容,但为了安全起见,您最好禁用它。您真的 100% 确定您的调试信息永远不会显示您想要保密的任何内容吗?我敢打赌答案是“不是 100%”,所以你最好把它关掉。

这是我刚刚编写的一个非常简单的示例:

WARNING: $accounts is not numeric, $accounts is an array;
$accounts = (user1@example.com, user2@example.com, ...)

假设由于某种奇怪的原因,显示了这样的错误。糟糕:用户的帐户将被泄露。当然你可能会说这是不可能的,框架 X 没有转储变量的内容,框架 Y 不能有这样的错误,你永远不会犯这样的错误,等等。但你能确定会一般来说,从来没有发生在你身上?安全使用并关闭它:这很简单,而且不花钱。