是否有必要在顶级包装每个例外?

时间:2012-02-20 07:56:11

标签: c# exception-handling

今天,有人告诉我,我们应该始终将每个例外都包装在框架的顶层。 原因是原始异常可能包含堆栈跟踪或消息中的敏感信息,尤其是堆栈跟踪。

我不知道,是否有任何规则/原则/模式?

4 个答案:

答案 0 :(得分:15)

  

今天,有人告诉我,我们应该始终将每个例外都包装在框架的顶层。

“总是”似乎有点多了。

与任何其他设计决策一样,您应该考虑成本和收益。

  

因为原始异常可能包含堆栈跟踪或消息中的敏感信息,尤其是堆栈跟踪。

实际上;异常可能包含敏感信息,攻击者可以使用堆栈跟踪。

  

有没有任何规则/原则/模式?

是。在您执行任何其他之前,尤其是在进行设计或代码更改之前,制作威胁模型。您正在询问安全问题,因此在制定良好的策略来缓解漏洞之前,您绝对必须了解威胁

威胁模型回答的核心问题应该是“我的应用程序的信任边界是什么?数据何时以及如何跨越边界?”这会暴露漏洞吗?攻击者可以在哪些威胁下取得好成绩?

如果您不确切了解信任边界,漏洞,威胁和攻击者是什么,那么在尝试设计安全系统以减轻威胁漏洞之前,先了解这些词是什么意思。 “编写安全代码2”是一个很好的起点。 (我的代码安全书第5章对消除异常漏洞提出了一些很好的建议,但它已经绝版了。也许我会在有一天的时间里把它放在博客上。)

数据可以跨越任意方向的信任边界;不受信任的客户端可能正在向您的服务器发送格式错误的数据,并且您的服务器可能正在向不可信任的客户端发送敏感的私有数据。

您的问题专门针对的威胁模型的特定方面是异常形式的数据。我没有告诉你,在我们发布.NET 1.0之前你实际上可以让框架给你一个例外,其中的文本类似于“你没有权限确定目录C:\ foo的名称”。 (很好。感谢您告诉我。我现在肯定不会使用该信息来攻击用户。)

显然,在我们发货之前很久就已经修好了,但是人们每天都在做道德等同。如果您有跨越信任边界的数据,您应该假设不受信任的一方的恶意用户将尝试在可信方面引起异常,并且将尝试从这些异常中尽可能多地了解系统。 不要让攻击者的工作更轻松。

您询问是否应该包装所有异常。也许。如果实际上你遇到了问题 - 如果包含敏感数据的异常可以跨越信任边界,那么包装异常是正确的。但也许它不是足够的。也许你不需要在边界上抛出异常,即使异常可以被消除。也许正确的做法是继续全红警报并说“嘿,我们得到了一个潜在敌对的第三方的不良数据引起的意外异常,所以让我们(1)禁止他们的IP,或者(2)将他们重定向到蜜罐服务器,或(3)警告安全部门,或(4)其他东西。“正确的解决方案取决于威胁,您还没有说明。

就像我说你需要做的第一件事是模拟威胁。在不彻底了解威胁的情况下,不要做出安全决策。

答案 1 :(得分:0)

是的,有一条规则:这是愚蠢的。

我们需要了解更多细节,但最后:

  • 您可以而且应该拥有异常的顶级处理程序。这不在您的框架中(即包装顶级),而是附加到appdomain(未处理的异常)。这允许您显示错误消息并写入日志等。

  • 最后,您应尽可能多地传播信息。规则是“抓住你可以处理的东西,传播你不能”。

  • 现在变得有趣了。 “敏感信息”是“信息有用且需要用于调试”。在最高标准上说“包装异常=原始进入内部异常属性”。

框架不应该向用户公开敏感信息,但这是特定于应用程序的(iis:自定义错误页面,窗口等等:最后的处理程序,没有向用户显示太多细节,因为用户并不关心)。

答案 2 :(得分:0)

Eric Lippert撰写了一篇很棒的博客,内容是关于应该在哪些例外情况下发现的。

Vexing exceptions

它没有直接回答你的问题,但它提供了一般异常处理的好主意。

答案 3 :(得分:-2)

在正常条件下为用户显示堆栈跟踪并不是最好的选择。 我使用DEBUG常量设置为“true”进行调试和开发,并在正常情况下设置为“false”,看看那个PHP示例

DEFINE("DEBUG" true);

function soap_error($soapFault)
{
if (DEBUG)
    {
        // full message with stack including sensitive info
        echo '<p class="error">SOAP error:</p><br />';
        echo '<p>'.$soapFault.'</p><br />';
        echo '<hr />';
    }
    else
    {
        // only error message           
        echo '<p class="error">SOAP error:</p><br />';
        echo '<p>'.$soapFault->getMessage().'</p><br />';
        echo '<hr />';
    }
}

您还可以使用日志文件来保存完整的错误堆栈。

在C#/ .NET中这更容易,因为你在Visual Studio中有构建配置,你可以在它们之间切换并使用类似的东西:

public static void myerrorhandler(Exeption e) 
 {
 #if (DEBUG) // you have DEBUG and RELEASE configurations by default
 yourErrorMessageFunction("This is error message and stack " + e.toString()); 
 #else
 yourErrorMessageFunction("This is only message" + e.Message());
 #endif
 }

Visual Studio正在添加和控制DEBUG常量(在“构建配置”中设置,您可以在那里自定义它。)