安全框架:异常管理 | 缓解措施
产品/服务 | 项目 |
---|---|
WCF | |
Web API | |
Web 应用程序 |
WCF - 不要在配置文件中包含 serviceDebug 节点
标题 | 详细信息 |
---|---|
组件 | WCF |
SDL 阶段 | 构建 |
适用的技术 | 泛型、NET Framework 3 |
属性 | 空值 |
参考 | MSDN、巩固王国 |
步骤 | 可将 Windows Communication Framework (WCF) 服务配置为公开调试信息。 不应在生产环境中使用调试信息。 <serviceDebug> 标记定义是否为 WCF 服务启用调试信息功能。 如果 includeExceptionDetailInFaults 特性设置为 true,则将来自应用程序的异常信息返回到客户端。 攻击者可以利用他们从调试输出中获取的附加信息,针对框架、数据库或者应用程序使用的其他资源展开攻击。 |
示例
以下配置文件包含 <serviceDebug>
标记:
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name=""MyServiceBehavior"">
<serviceDebug includeExceptionDetailInFaults=""True"" httpHelpPageEnabled=""True""/>
...
在服务中禁用调试信息。 可通过在应用程序的配置文件中删除 <serviceDebug>
标记来实现此目的。
WCF - 不要在配置文件中包含 serviceMetadata 节点
标题 | 详细信息 |
---|---|
组件 | WCF |
SDL 阶段 | 构建 |
适用的技术 | 泛型 |
属性 | 泛型、NET Framework 3 |
参考 | MSDN、巩固王国 |
步骤 | 有关服务的公开信息可能会给攻击者提供有用的洞察数据,使他们知道如何攻击服务。 <serviceMetadata> 标记会启用元数据发布功能。 服务元数据可能包含不应该提供给公众访问的敏感信息。 最起码,应该只允许受信任的用户访问元数据,确保不必要的信息不会公开。 当然,更好的做法是完全禁用元数据发布功能。 安全的 WCF 配置不包含 <serviceMetadata> 标记。 |
确保在 ASP.NET Web API 中进行适当的异常处理
标题 | 详细信息 |
---|---|
组件 | Web API |
SDL 阶段 | 构建 |
适用的技术 | MVC 5、MVC 6 |
属性 | 空值 |
参考 | ASP.NET Web API 中的异常处理、ASP.NET Web API 中的模型验证 |
步骤 | 默认情况下,ASP.NET Web API 中大多数未捕获的异常将转换成状态代码为 500, Internal Server Error 的 HTTP 响应 |
示例
若要控制 API 返回的状态代码,可按如下所示使用 HttpResponseException
:
public Product GetProduct(int id)
{
Product item = repository.Get(id);
if (item == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return item;
}
示例
若要进一步控制异常响应,可按如下所示使用 HttpResponseMessage
类:
public Product GetProduct(int id)
{
Product item = repository.Get(id);
if (item == null)
{
var resp = new HttpResponseMessage(HttpStatusCode.NotFound)
{
Content = new StringContent(string.Format("No product with ID = {0}", id)),
ReasonPhrase = "Product ID Not Found"
}
throw new HttpResponseException(resp);
}
return item;
}
若要捕捉类型不是 HttpResponseException
的未经处理的异常,可以使用异常筛选器。 异常筛选器实现 System.Web.Http.Filters.IExceptionFilter
接口。 编写异常筛选器的最简单方法是从 System.Web.Http.Filters.ExceptionFilterAttribute
类派生,并重写 OnException 方法。
示例
下面是可将 NotImplementedException
异常转换为 HTTP 状态代码 501, Not Implemented
的筛选器:
namespace ProductStore.Filters
{
using System;
using System.Net;
using System.Net.Http;
using System.Web.Http.Filters;
public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
}
}
}
}
可通过多种方法注册 Web API 异常筛选器:
- 按操作
- 按控制器
- 全局
示例
要将筛选器应用到特定的操作,请将筛选器作为特性添加到该操作:
public class ProductsController : ApiController
{
[NotImplExceptionFilter]
public Contact GetContact(int id)
{
throw new NotImplementedException("This method is not implemented");
}
}
示例
要将筛选器应用到 controller
中的所有操作,请将筛选器作为特性添加到 controller
类:
[NotImplExceptionFilter]
public class ProductsController : ApiController
{
// ...
}
示例
要将筛选器全局应用到所有 Web API 控制器,请将筛选器的实例添加到 GlobalConfiguration.Configuration.Filters
集合。 此集合中的异常筛选器将应用到任何 Web API 控制器操作。
GlobalConfiguration.Configuration.Filters.Add(
new ProductStore.NotImplExceptionFilterAttribute());
示例
对于模型验证,可按如下所示,将模型状态传递给 CreateErrorResponse 方法:
public HttpResponseMessage PostProduct(Product item)
{
if (!ModelState.IsValid)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
// Implementation not shown...
}
请查看参考部分中的链接,了解有关 ASP.NET Web API 中异常处理和模型验证的更多详细信息
不要在错误消息中公开安全详细信息
标题 | 详细信息 |
---|---|
组件 | Web 应用程序 |
SDL 阶段 | 构建 |
适用的技术 | 泛型 |
属性 | 空值 |
参考 | 空值 |
步骤 | 常规错误消息将直接提供给用户,其中不包含敏感的应用程序数据。 敏感数据的示例包括:
捕获应用程序中的所有错误、提供常规错误消息,以及在 IIS 中启用自定义错误,都有助于防止信息泄漏。 SQL Server 数据库和 .NET 异常处理以及其他错误处理体系结构提供的信息特别详细,能够为恶意用户分析应用程序带来极大的帮助。 不要直接显示派生自 .NET Exception 类的类的内容,确保采取适当的异常处理,避免无意中向用户直接引发意外的异常。
|
实现默认错误处理页
标题 | 详细信息 |
---|---|
组件 | Web 应用程序 |
SDL 阶段 | 构建 |
适用的技术 | 泛型 |
属性 | 空值 |
参考 | 编辑 ASP.NET 错误页设置对话框 |
步骤 | 如果 ASP.NET 应用程序失败并导致 HTTP/1.x 500 内部服务器错误,或者某项功能配置(例如请求筛选)阻止显示页面,会生成错误消息。 管理员可以选择是要让应用程序向客户端显示友好的消息、向客户端显示详细的错误消息,还是只向 localhost 显示详细的错误消息。 web.config 中的
打开应用程序/站点的 |
在 IIS 中将部署方法设置为 Retail
标题 | 详细信息 |
---|---|
组件 | Web 应用程序 |
SDL 阶段 | 部署 |
适用的技术 | 泛型 |
属性 | 空值 |
参考 | 部署元素(ASP.NET 设置架构) |
步骤 |
通常,主要面向开发人员的开关和选项(例如,对失败的请求进行跟踪和调试)是在现行开发的过程中启用的。 建议将任何生产服务器上的部署方法设置为 retail。 打开 machine.config 文件,确保 |
异常应安全失败
标题 | 详细信息 |
---|---|
组件 | Web 应用程序 |
SDL 阶段 | 构建 |
适用的技术 | 泛型 |
属性 | 空值 |
参考 | 安全失败 |
步骤 | 应用程序应安全失败。 对于根据所做的特定决策返回布尔值的任何方法,应该谨慎创建异常块。 许多逻辑错误就是因为在编写异常块时漫不经心,使安全问题日积月累造成的。 |
示例
public static bool ValidateDomain(string pathToValidate, Uri currentUrl)
{
try
{
if (!string.IsNullOrWhiteSpace(pathToValidate))
{
var domain = RetrieveDomain(currentUrl);
var replyPath = new Uri(pathToValidate);
var replyDomain = RetrieveDomain(replyPath);
if (string.Compare(domain, replyDomain, StringComparison.OrdinalIgnoreCase) != 0)
{
//// Adding additional check to enable CMS urls if they are not hosted on same domain.
if (!string.IsNullOrWhiteSpace(Utilities.CmsBase))
{
var cmsDomain = RetrieveDomain(new Uri(Utilities.Base.Trim()));
if (string.Compare(cmDomain, replyDomain, StringComparison.OrdinalIgnoreCase) != 0)
{
return false;
}
else
{
return true;
}
}
return false;
}
}
return true;
}
catch (UriFormatException ex)
{
LogHelper.LogException("Utilities:ValidateDomain", ex);
return true;
}
}
如果发生某种异常,上述方法始终返回 True。 如果最终用户提供了浏览器支持的、但 Uri()
构造函数不支持的错误格式 URL,则会引发异常,受害者会转到有效但格式不当的 URL。