密码是否应该在错误消息中显示?

信息安全 密码 php 错误处理
2021-08-31 23:34:03

我对PHP 的 PDO 类感到恼火。正如您在警告说明中看到的:如果未捕获到异常,默认情况下它会显示数据库密码(当出现显示错误时,对于新手网站管理员来说,在生产服务器中很可能出现这种情况)。

这是我与 PHP 开发人员的争论

我:

泄露密码是很不寻常的,因为 MySQL 本身隐藏密码以进行调试或发生错误时。例如,MySQL 的典型输出是“用户 'root'@'localhost' 的访问被拒绝(使用密码:YES)”它从不显示密码。

正如我们所知,许多使用依赖 PDO 的第三方软件的新手程序员或最终用户可能并不关心 display_errors 是否被关闭。

我认为这是一个安全风险。例如,恶意用户可以运行爬虫并使用字符串“Fatal error: Uncaught exception 'PDOException'”搜索网站,他们现在可以获取密码。

我希望你考虑到这一点。

PHP 核心开发:

是的,使用 display_errors=on 运行生产服务器并使用参数打印回溯是一种安全风险。这就是为什么你永远不应该这样做。

PHP Core Dev 似乎更愿意依靠最终用户来关闭错误显示。尽管他们发出了警告,但鉴于 MySQL 本身(一个 PDO 正在抽象)没有透露密码而 PDO 更愿意透露密码,这似乎仍然是不可接受的。

您认为 PHP 核心开发人员在错误时泄露密码方面是正确的吗?

4个回答

此问题已加载,但我完全同意答案:不,密码不应在错误消息中显示。未经用户明确同意,不得在任何地方写出密码。考虑以下角色以及他们如何访问用户刚刚输入的错误密码:

  • 用户。那是唯一应该能够知道她刚刚输入的内容的角色。美好的。
  • 有人肩冲浪。大多数密码输入表格将密码隐藏在****; 在屏幕上显示密码会破坏这种保护。如果密码未在生产环境中显示,则这无关紧要(但更多内容见下文)。
  • 密码所在系统的管理员。流氓管理员通常可以通过插入一些秘密的日志记录代码来获取密码,但这是一种主动攻击,有被检测到的风险。即使密码只显示在开发配置中,也意味着代码就在那里,并且可以通过一次看似无辜的更改许多配置变量来重新激活。对管理员隐藏密码是一种常见的做法:我所见过的任何非 Web 通用公共软件都不会记录密码;当用户在他们面前输入密码时,系统管理员和 IT 支持人员通常会避开眼睛。
  • 已收到错误报告的应用程序开发人员。该角色永远不应该访问密码。在错误痕迹中包含密码,即使它们只显示给那些从痕迹中最常用的人,也是不好的。
  • 攻击者窃取错误跟踪的备份,或者由于配置错误(例如意外设置)而能够看到回溯display_errors=on

错误密码作为资产的价值取决于它是什么。如果是正确密码的拼写错误,则错误密码实际上与正确密码一样有价值。如果密码是另一个站点的密码(哎呀,我在测试环境的用户登录表单中输入了我的生产站点密码),它实际上与该站点的凭据一样有价值。泄露错误密码具有泄露高价值资产的高风险。

开发者的反应非常不满意:

是的,使用 display_errors=on 运行生产服务器并使用参数打印回溯是一种安全风险。这就是为什么你永远不应该这样做。

首先,即使在开发环境中也存在强烈的安全问题,即使日志只显示给那些合法看到它们的人。

其次,一切“都是安全风险”,但有些风险比其他风险更严重。回溯可以揭示机密信息,这些信息可能本身就是资产,也可能成为攻击路径的一个步骤。这并不像在银盘上分发密码那么糟糕。

最重要的是,这个回应显示了一种非常狭隘的安全观:“如果你正确使用我的软件,你将不会有任何直接风险”。即使这是真的(不是),安全也是一个整体问题。很难确保大型系统的每个组件都按照该组件的作者的意图准确使用。因此组件必须是健壮的——这也被称为“纵深防御”。像“从不记录密码”这样的规则比“不要向那些不应该看到密码的人(谁?)显示回溯,并且无论如何都关闭它们(如果你需要它们,太糟糕了)”更简单。

识别什么是密码,什么不是密码可能会有困难。可以说,隐藏密码会让人期望密码总是被隐藏,如果不隐藏,这是一件坏事。我认为成功率足以证明在这里尽最大努力是合理的。

在异常期间,我绝不会出于任何原因交回凭据,这取决于开发人员执行打印 var_dump 之类的操作来验证他们传入的内容,其他任何事情都可能泄漏不应该的数据。

当然,最好的做法是永远不要向用户显示异常消息,在其他情况下,它可以很容易地被用来进一步利用该站点,但这太容易了,我看不出为什么你会传递那种细节的明确原因背部。

MySQL 的错误要好得多(用户@地址,密码是/否),信息丰富但没有太多数据泄漏(尽管可以说我不希望人们知道内部地址或我的身份验证机制)。

PHP 也以根本没有真正握住你的手而闻名,当你做错事时会把你扔给鲨鱼(因为它的文档记录很差),所以看起来很正常。

PDO 的做法是绝对错误的,没有任何借口。

错误消息,即使在正确配置的系统上,最终也会出现在各种各样的地方——错误日志、面向用户的错误消息等。人们会犯错误,暴露数据库凭据的风险太高了,而好处(查明错误的密码)充其量是微不足道的。发生此类错误时,罪魁祸首可能是无效 SQL、违反约束、网络问题或损坏的 DB 服务器。即使密码确实错了,也没有理由显示出来;只需抛出“无效的数据库凭据”或“拒绝访问数据库”之类的消息就足够了;如果您怀疑密码不是您想要的密码,有很多方法可以专门调试它。即使完全没有风险,

如果您浏览 PHP 错误存储库,我相信您会发现很多关于这个问题和类似问题的讨论。简而言之:这个问题已经被讨论到死了,负责的开发人员似乎不同意当前的行为是有问题的,所以它不太可能很快改变。

这意味着您必须自己提出解决方案。一个有效的最后一根稻草解决方案是配置一个全局异常处理程序,它只是str_replace带有一系列星号的真实密码。或者,您可以强制 PDO 不抛出,但是您会失去基于异常的错误处理的舒适性,并且您仍然必须清理 PDO 的错误消息(只是您现在必须自己繁琐地将它们从 PDO 和 PDOStatements 中剥离出来)。

只需使用 str_replace() 隐藏密码。

// Connect using PDO
try 
{   
    $this->dbh = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME , DB_USER , DB_PASS); 
    $this->dbh->setAttribute(PDO::ATTR_ERRMODE , PDO::ERRMODE_EXCEPTION);           
}
catch(PDOException $e)
{
    echo str_replace(DB_PASS, ' *** LOOK @CONFIG FOR YOUR SECRET PASSWORD! *** ' , $e);
}