本文演示Enterprise Library – Exception Handling Application Block 异常管理模块的使用,如何将异常日志记录添加到应用程序中,以及如何使用Replace Handler隐藏敏感信息。本文由
http://blog.entlib.com 开源ASP.NET博客平台小组根据EntLib HOL手册编译提供,欢迎交流。
练习二:异常管理策略
本文练习如何使用代码访问安全来保护应用程序功能,并使用Exception Handling Application Block的Replace Handler隐藏敏感信息在客户端的显示。
1. 首先打开\Enterprise Library 4.1 HOL\CS\Exception Handling\exercises\ex02\begin 目录下的Puzzler2.sln 项目文件。接着打开PuzzlerService 项目中的DictionaryService.cs 代码文件,DictionaryService类作为Dictionary类的服务接口(Service Interface),在这个类中,在发生异常信息到客户端之前,实现了异常信息的过滤和转换。
2. 对Add Word 功能实施代码访问安全(Code Access Security)
打开PuzzlerService项目中的Dictionary.cs 代码文件,找到AddWord方法,添加安全属性,如下所示:
[PrincipalPermission(SecurityAction.Demand, Role = "EntLib.com Administrator")]
public static Boolean AddWord(string wordToAdd)
{
if (!IsWord(wordToAdd))
{
// It is not alphabetic! Throw an exception
throw new ApplicationException(
"Word to add does not consist of alphabetic letters");
}
if (Dict[wordToAdd] == null)
{
Dict.Add(wordToAdd, wordToAdd);
}
return true;
}
上述方法仅允许EntLib.com Administrator角色的成员调用(注:是在Dictionary.cs文件上,而不是DictionaryService.cs 文件上做上述修改。)
3. 运行应用程序
选择Debug | Start Without Debugging菜单项运行应用程序,在Word To Check 文本框输入一个单词(如abc123),将调用AddWord方法,抛出SecurityException异常,可以检查事件日志看到如下信息:
SecurityException可能从Server端序列化,传送到Client端,且有可能包含有敏感信息,对攻击者提供帮助。因此,我们希望在Server端捕获并记录安全异常,然后传递包含较少的异常信息到Client端。
4. 配置应用程序替换SecurityException
在PuzzlerUI项目中,使用EntLib 附带的配置管理工具打开app.config 配置文件(具体操作可以参考Data Access Application Block的学习手册,这里不再重复了)。
app.config 配置文件中已经包含了一个空的policy,名称为Service Policy。默认情况下,这个policy是空的,因此异常信息将在catch代码块中重新抛出,事实上该policy没有任何作用。
下面选择Service Policy 节点,然后选择 New | Exception Type 菜单项,在弹出对话框中选择mscorlib 的System.Security.SecurityException类型,并点击 OK 按钮,如下图所示。
注:你可以使用类型选择器(Type Selector)轻松过滤Exception类型。
接着选择 Service Policy |SecurityException 节点,并设置如下属性:
PostHandlingAction = ThrowNewException
然后选择 Service Policy |SecurityException 节点,添加一个新的Logging Handler,并设置如下属性:
FormatterType = TextExceptionFormatter
LogCategory = General
Title = Security Exception in Service Layer
下一步再选择 Service Policy | SecurityException 节点,添加新的Replace Handler,并设置相应属性:
ExceptionMessage = Unauthorized Access
ReplaceExceptionType = System.Security.SecurityException (from mscorlib)
尽管上述操作还是保留相同的Exception类型,但通过创建一个新的SecurityException,可以对Client端不提供任何stack信息或内部安全异常信息,这样可以达到安全目的。
5. 设置应用程序遇到安全异常时退出
选择UI Policy节点,添加一个新的Exception 类型 – System.Security.SecurityException,并设置如下属性:PostHandlingAction = NotifyRethrow
将PostHandlingAction 属性设置为NotifyRethrow时,Application.ThreadException 事件的handler将重新抛出异常。重新抛出的异常为未捕获异常,.NET Framework的CLR将强制关闭应用程序。
static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
HandleException(e.Exception, "UI Policy");
}
下一步再选择 UI Policy | SecurityException 节点,添加新的Logging Handler,并设置如下属性:
FormatterType = TextExceptionFormatter
LogCategory = General
Title = Security Exception in UI Layer
最后,别忘记保存app.config 配置文件。
6. 测试Replace Handler
选择Debug | Start Without Debugging 菜单项,运行应用程序。
在Word To Check 文本框中,输入一个错误的单词(确保错误的图标出现),然后点击Add Word按钮。将弹出一个对话框,显示Unhandled exception消息。
下面打开Event Log,查看事件日志,这一次Event Log 中将有三条Excpetion记录。
第一条是Dictionary.cs抛出的SecurityExcepiton异常,在Service Layer(DictionaryService.cs)捕获,应用Service Policy。
ExceptionPolicy
.HandleException(ex, "Service Policy");
将异常记录到Server端的事件日志(包含有所有信息)。
第二条是替换过的SecurityException异常,在Startup.cs的ThreadException handler中捕获(
http://blog.EntLib.com 开源博客小组注:这里捕获的异常是Server端重新抛出的异常),并应用 UI Policy。
HandleException(e.Exception, "UI Policy");
将异常记录到Client端的事件日志(本范例是同一台机器)。前面在app.config中配置重新抛出异常,因此将重新抛出上述接收到的SecurityException异常。
第三条是前一步重新抛出的SecurityException 被AppDomain的UnhandledException handler捕获(在Application.Run线程之外抛出),并应用Unhandled Policy。
HandleException((System.Exception)e.ExceptionObject, "Unhandled Policy");
将记录异常信息,并显示一个消息对话框,提醒用户应用程序有错误。AppDomain UnhandledException handler并不好吸收该异常,因此异常将继续传递到Runtime或者Debugger调试器,这将导致一个标准的unhandled exception对话框弹出。
为了准确理解上述的学习教程,建议仔细阅读下面的这段文字。这段文字摘录自Enterprise Library – Exception Handling Application Block帮助文档,介绍了Exception Type的配置。
Configuring Exception Types
Each exception policy can be configured to handle specific exception types. An application passes the exception to be handled and the name of the policy that should be used to handle the exception to the Exception Handling Application Block. The application block looks at the policy to see if it has been configured to handle exceptions of that type.
If it finds a match, the application block executes the series of exception handlers. The application block tries to match the exception type to the most specific type of exception listed in the configuration file. If it does not find a match, the application block looks for base class exception types.
In this way, an application can be configured for particular actions for specific exception types (for example, it can wrap or replace exceptions of type System.SecurityException with a custom application exception type), but it can have different actions for more generic exception types (for example, it can log exceptions of type System.Exception). Each exception type can be configured to indicate the action the application block will take after the chain of exception handlers runs for that exception type.
参考文档:
Exception Handling Application Block Hands-On Labs for Enterprise Library