在(桌面)客户端应用程序中记录错误详细信息

信息安全 日志记录 客户端 披露 错误处理
2021-09-11 14:29:54

从安全的角度来看,我对如何正确记录客户端-服务器应用程序的客户端部分(Java Swing)的错误进行了辩论。

我认为将异常和堆栈跟踪等错误细节暴露给“不受信任”的用户是一种不好的做法,并且至少会通过信息泄露(内部结构、依赖项等)削弱您的应用程序安全性,这是常识。

服务器端的解决方案可以通过确保不向用户公开任何错误详细信息并将详细信息安全地存储在服务器上来解决。这样,在需要时,专门的人员可以在调查期间查找错误详细信息。

但是,如何在不将错误信息暴露给用户的情况下将错误详细信息存储在客户端上呢?

我想到了几件事,但每件事在某些方面都有缺陷。

  1. 将错误详细信息发送到存储它们以供以后查找的专用服务器。
    • 如何发送通信层问题的错误详细信息(根本无法进行外部通信)?
    • 无法从客户端网络访问您的日志服务器(防火墙规则、代理等)。
  2. 非对称加密错误详情
    • 记录期间的潜在性能影响。
    • 错误调查过程中必须解密错误细节,这使得过程更加繁琐。

另一方面,您可以争辩说,从客户端应用程序公开错误详细信息不如从服务器应用程序公开错误详细信息那么重要。

  • 用户已经有权访问可用于收集内部信息(逆向工程)的客户端二进制文件。
  • 大多数通信细节可以通过嗅探客户端和服务器之间的流量来收集。
  • 关于客户端应用程序的内部知识(在大多数情况下)不如关于服务器的有价值,因为客户端主要充当 UI,而基本业务逻辑驻留在服务器上。

从安全的角度来看,在客户端存储错误详细信息的“最佳实践”或最佳折衷方案是什么?或者换一种说法,是否值得为客户端应用程序隐藏错误详细信息(异常、堆栈跟踪等)?

3个回答

让我们尝试使用威胁建模技术来研究这个问题。

我们试图保护什么?

客户端日志供支持人员稍后分析。

我们的风险是什么?

如果客户端处理程序中断并存储在客户端,这会导致什么?我们是否正在考虑进行本地命令执行、日志注入等?了解应用程序提供的内容以及可能受到损害的内容至关重要。

是的,客户端总是危险的,这并不意味着它不能被保护或理解。

我们的攻击者是什么样的?

  1. 基本用户:抓取应用程序的历史,尝试搜索系统上的文件,主要进行基本的查找和侦察。
    • 风险:尝试了解破坏 UI 控件的内容以及它们如何更改输出并从中获得乐趣。如果日志包含泄露的秘密,他们将能够获取它们并滥用系统(或勒索组织)。
    • 缓解措施:采用对称加密可以保护日志,因为用户没有足够的知识来对应用程序进行逆向工程并获取密钥。如果日志清理输入并且不输出机密,则几乎不存在风险。
  2. 高级用户:在基本用户之上,该用户能够更深入地了解正在破坏的内容,并尝试对服务进行模糊测试以强制执行未处理的行为(这可能会破坏它)。此用户能够逆向工程并从应用程序中提取字符串(如果已存储)。
    • 风险:通过识别应用程序的行为方式,该用户能够研究客户端应用程序,识别其弱点,并可能发现其中的问题(DoS、本地执行等)。在大多数情况下,该用户将向应用程序背后的公司报告漏洞或问题。
    • 缓解措施:使用只有支持人员知道的代码创建错误映射。用户将能够知道触发的异常,但不知道它是如何准确破坏的以及发生了什么的详细信息。成为盲目攻击(更难实现)。正如你提到的,可以使用非对称加密。为了加快速度,您可以做的是使用带有密钥的随机数来创建临时会话,这需要用户立即中断日志并查找它们,否则只有支持才能获得它。
  3. 恶意用户:类似于高级用户,有明确的造成损害的意图。
    • 风险:用户构建漏洞以试图拥有其他用户的系统,破坏公司声誉等。
    • 缓解措施:在这种情况下,如果应用程序实际上是可利用的,那么用户将已经确定正在发生的事情,并且在这个阶段加密几乎没有意义。日志只会确认攻击者的分析。由于这与日志特别相关,因此应该使用非对称加密,如果启动或完成某个活动(系统执行任务所需时间太长、执行系统命令、网络渗漏等),可能会触发回调。 )。这允许主动控制,这是保护您的用户群的最佳机制。

在所有情况下,网络攻击都没有得到满足。nonce 是一个公共实体,因此总是可以检索的。否则,不会通过这些渠道传达任何具体的秘密。我主要关注应用程序行为。没有与上述方法相关的重大网络攻击。

我认为这里一开始有一点误解。您可能绝对不希望在错误请求时输出服务器异常,并可能使用 GUID 来跟踪服务器对客户端支持调用的请求。因为,正如你所说,暴露不需要的细节可能会扩大服务器的攻击面,如果被利用通常会造成伤害。

但是现在,从客户的角度来看,这样的想法并不一定适用。问问自己在客户端需要保护什么。

  • 保护源代码和公司的IP?

不要依赖这个。使用适当的混淆器,它还可以连贯地混淆堆栈跟踪,并与源映射配对以在调用支持时“去混淆”日志。

  • 防止服务器漏洞?

永远不要相信来自服务器端的用户输入。假设客户端是流氓,被某人操纵。使用身份验证、验证输入、执行利用率检查。

  • 实施 DRM/付费墙

这是另一种说法。混淆您的代码,使破解 DRM 方案变得困难重重,但仍然在服务器端进行验证、验证、验证。如果用户帐户没有信用,请不要回答客户。

当服务器健壮时,堆栈跟踪没有区别

其他想法:

可以通过信息泄露(内部结构、依赖关系等)削弱您的应用程序安全性。

这仍然可以通过适用于 Java 世界的体面的反编译器来实现。依赖项要么存储为 jar,要么嵌入到 fat jar 中。如果我有您的 Java 二进制文件,我什至可以尝试猜测您所依赖的框架的确切版本。尤其是混淆的时候。

从安全的角度来看,在客户端存储错误详细信息的“最佳实践”或最佳折衷方案是什么?

如果我必须说出一个名字,JetBrain 的 IntelliJ IDEA Ultimate 是一个付费桌面应用程序,它会生成未加密的日志,我可以在发送给支持之前查看这些日志。该软件经过混淆处理,以防止破坏其 DRM/许可方案。然而,它像任何其他客户端方案一样经常被破坏和修复

我认为最佳实践不应该在 GUI 中向用户显示完整的异常和堆栈跟踪。向他们显示一条友好的信息,例如“抱歉,请联系我们的服务台”

如果您想在本地存储错误以在以后合理的情况下将它们同步到母舰,请不要将它们存储在明文文件或 GUI 的屏幕上。将它们存储在具有受限权限的文件中。或者将它们存储在加密的本地文件中。或者将它们存储在受所有其他敏感数据保护的本地数据库中。

如果攻击者已经在盒子上并四处窥探,他们可能对他们的错误消息不感兴趣。如果他们真的要闯入您的应用程序,他们可能会使用调试器和/或反转它,因此可能不会太在意您的错误消息。

记录错误时要考虑的一件大事是确保您清除敏感信息,例如密码、客户数据、信用卡、ssns、PII 等,以免它们出现在您的日志中。