如何在 IIS 7.0 中使用 HTTP 详细错误

作者:IIS 团队

介绍

每个网站管理员或 Web 开发人员都在其浏览器中看到过“404 - 找不到文件”、“401 - 未授权”或“500 - 服务器错误”消息。 本文可帮助你了解 IIS 生成这些错误的方式和原因,以及如何配置这些错误。

许多人可能认为,生成错误消息似乎并不能证明全文的合理性。 但错误远不止表面上看到的那样。 错误消息是一个敏感主题,因为每个错误都会揭示比你想要透露的更多有关网站的信息。 某人可以收集的有关网站的信息越多,你被黑客入侵的可能性就越大。 搜索“谷歌黑客”或“跨站点脚本”会显示有关此主题的大量信息。

但是,错误消息也是解决问题的宝贵工具。 当发生错误时,开发人员和网站管理员需要尽可能多的详细信息。 理想情况下,错误消息会提供有关如何解决问题的建议。 下面介绍 IIS 如何解决这些根本对立的目标。

错误,哪些错误?

本文讨论 HTTP RFC 中指定的 HTTP 错误(RFC 2616 - 第 6.1.1 节)。 HTTP 错误始终通过将状态代码大于 400 的响应发送回请求客户端来表示。

客户端错误数

介于 400 到 500 之间的状态代码指定客户端所犯的错误,例如语法错误或对不存在的资源的请求。 可以通过从所选网站请求虚假 URL 来尝试此操作,例如:http://<IIS7Server>/this_resource_does_not_exist。 收到“404 - 找不到文件”错误。

服务器错误数

以 500 开头的状态代码是由服务器引起的错误。 IIS 系统上出现 500 错误的最常见原因包括:

  • 包含语法错误的 ASP 或 ASPX 页
  • 无法读取 Web 服务器配置或应用程序配置,或者配置无效
  • 站点已停止

需要注意的是,像 IE 这样的浏览器通常会将从 Web 服务器返回的错误替换为自己的错误。 这使得故障排除变得更加困难。 在 IE 中,你可以禁用此功能。 转到“工具”菜单,选择“Internet 选项”,单击“高级”选项卡,找到“显示友好的 HTTP 错误消息”复选框并取消选中该复选框。 若要查看原始响应,请使用 IIS 6.0 资源工具包中的 WFETCH 等 HTTP 工具(请参阅“相关链接”)。

IIS 中的 HTTP 错误

当 httpError 模块 (custerr.dll) 遇到错误时,可能会发生两种情况:

  • 生成自定义错误
  • 生成详细的错误

自定义错误是普通网站用户看到的错误页面。 它们包含对错误发生原因的简短错误描述,但不包含其他内容。 下面是请求不存在的资源时生成的自定义错误,例如:http://<IIS7Server>/this_resource_does_not_exist

Screenshot of the the H T T P Error 404 file or directory not found webpage in Internet Explorer.

详细的错误适用于本地管理员和开发人员。 它们应提供有助于立即解决问题的信息。 下面是同一请求的示例,但现在返回详细的错误:

Screenshot of the Server Error in Default Web Site Application webpage, showing a Cause and Solution section for the error.

这并不安全,因为详细的错误包含有关网站内部工作的信息。 只有受信任的人员才能看到详细的错误。 确保这一点的唯一方法是仅在请求来自本地计算机时生成详细的错误。 只要请求不是本地请求,就会生成自定义错误。 查看以下流程图:

Diagram of the Status Substatus, Entity Body, and Set Error's path of creating a detailed error.

数据流

第一个:错误检查

如果即将发送响应,httpError 模块将收到通知(RQ_SEND_RESPONSE 通知)。 httpError 模块检查此响应的状态代码,如果状态代码不大于 400,则立即返回。

第二个:自定义错误或详细的错误

下一个检查由请求来源(请求是本地请求还是远程请求)和 errorMode 属性的设置确定。 errorMode 属性设置为 DetailedLocalOnly,这意味着将为每个远程请求生成“自定义错误”。 如果 errorMode 设置为“自定义”,则所有错误响应都将变为“自定义错误”。 如果 errorMode 设置为“详细”,则所有错误响应都将变为“详细的错误”。 下表阐明了此行为:

errorMode 请求来源 操作
DetailedLocalOnly(默认值) Local 详细的错误
DetailedLocalOnly(默认值) 远程 自定义错误
自定义 Local 自定义错误
自定义 远程 自定义错误
详细 Local 详细的错误
详细 远程 详细的错误

如果 httpError 模块确定必须生成“自定义错误”,则会查看其配置,看看是否可以找到匹配的错误。 如果找到匹配项,则会发送静态文件、重定向请求或执行指定的 URL。 如果找不到匹配项,IIS 将发送包含状态代码的基本单行消息。 下一部分详细介绍了“自定义错误”配置。

如果 custerr.dll 确定必须生成“详细的错误”,则需要另一个检查。 如果模块使用自己的错误描述覆盖响应的实体,则 IIS 不会触及响应。 它可能包含有价值的信息。 ASP.NET 是一个很好的示例。 ASP.NET 错误响应的实体可能包含异常堆栈及其自己的错误描述。 只有当响应的实体正文为空时,才会生成详细的错误。

<httpErrors> 配置

下面是在全新安装时获取的 IIS 自定义错误部分:

<httpErrors>
    <error statusCode="401" prefixLanguageFilePath="c:\inetpub\custerr" path="401.htm" />
    <error statusCode="403" prefixLanguageFilePath="c:\inetpub\custerr" path="403.htm" />
    <error statusCode="404" prefixLanguageFilePath="c:\inetpub\custerr" path="404.htm" />
    <error statusCode="405" prefixLanguageFilePath="c:\inetpub\custerr" path="405.htm" />
    <error statusCode="406" prefixLanguageFilePath="c:\inetpub\custerr" path="406.htm" />
    <error statusCode="412" prefixLanguageFilePath="c:\inetpub\custerr" path="412.htm" />
    <error statusCode="500" prefixLanguageFilePath="c:\inetpub\custerr" path="500.htm" />
    <error statusCode="501" prefixLanguageFilePath="c:\inetpub\custerr" path="501.htm" />
    <error statusCode="502" prefixLanguageFilePath="c:\inetpub\custerr" path="502.htm" />
</httpErrors>

你会看到,如果响应的状态代码为 401,IIS 将返回名为 401.htm 的文件。

子状态代码

许多 HTTP 错误都具有子状态。 IIS 默认的“自定义错误”配置不区分基于子状态的代码。 如果输入错误凭据 (401.1),或者因访问文件的权限无效而被拒绝访问 (401.3),则会发送相同的“自定义错误”页面。 可以在日志文件中或通过“详细的错误”查看不同的子状态代码。 下面是 IIS 生成的不同 404 子状态代码的列表:

状态 说明
404.1 找不到站点
404.2 被策略拒绝。 限制列表中不允许请求 ISAPI 或 CGI 程序。
404.3 静态文件处理程序的 MimeMap 中没有文件,因此拒绝了请求。
404.4 找不到用于处理请求的处理程序。
404.5 请求筛选模块拒绝了请求中的 URL 序列。
404.6 请求筛选模块拒绝了请求的 HTTP 谓词。
404.7 请求筛选模块拒绝了请求的文件扩展名。
404.8 请求筛选模块拒绝了特定的 URL 段(两个斜杠之间的字符)。
404.9 IIS 拒绝处理隐藏文件。
404.11 请求筛选模块拒绝了双重转义的请求。
404.12 请求筛选模块拒绝了包含高位元字符的请求。
404.14 请求筛选模块拒绝了 URL 过长的请求。
404.15 请求筛选模块拒绝了查询字符串过长的请求。
413.1 请求筛选模块拒绝了(请求和实体正文)过长的请求。
431 请求筛选模块拒绝了太长的标头。

可将 httpErrors 部分配置为显示特定子状态代码的“自定义错误”。 如果请求的具有文件扩展名的文件未包含在 IIS MimeMap(<staticContent> 配置部分)中,将以下行添加到 httpErrors 配置部分后,IIS 将返回 404_3.htm。

<error statusCode="404" subStatusCode="3" prefixLanguageFilePath="c:\inetpub\custerr" path="404_3.htm" />

下面介绍如何使示例正常工作:

  1. 将上面的条目添加到 httpErrors 配置部分。
  2. c:\inetpub\custerr\en-us 目录中创建名为 404_3.htm 的文件。
  3. c:\inetpub\wwwroot 目录中创建名为 test.yyy 的文件。
  4. 现在请求 http://localhost/test.yyy

文件扩展名 .yyy 不是 IIS MimeMap 的一部分,并且静态文件处理程序不提供该文件扩展名。

IIS 中的新增功能:特定语言的自定义错误

每个较新的浏览器都包含客户端的语言作为请求头。 下面是此标头的外观示例:

Accept-Language: en-us

接受语言的语法和注册表在 RFC1766 中指定。

生成错误时,IIS 在查找其返回的自定义错误文件时会考虑此标头。 它使用以下逻辑生成自定义错误的路径:

prefixLanguageFilePath 配置设置(例如 c:\inetpub\custerr)+
客户端发送的 Accept-Language 标头(例如 en-us)+
路径配置设置(例如 404.htm)

示例:

如果浏览器发送对不存在的资源的请求,并且“Accept-Language”标头的值为“en-us”,则返回的文件将位于 c:\inetpub\custerr\en-us\404.htm

例如,如果你来自德国,则建议错误消息使用德语。 为此,必须安装适用于德语的 Windows Vista 语言包。 这将创建其中包含自定义错误文件的 c:\inetpub\custerr\de-DE 目录。 现在,如果浏览器发送值为“de-DE”的“Accept-Language”标头,则返回的文件将位于 c:\inetpub\custerr\de-DE\404.htm

如果目录“de-DE”不存在,IIS 将始终回退到系统语言。

注意

Internet Explorer 允许配置 Accept-Language 标头。 转到“工具”>“Internet 选项”,选择“常规”选项卡,然后单击“语言”按钮。

自定义错误选项

在上面的示例中,IIS 将文件的内容作为自定义错误响应发送。 IIS 还有另外两种响应错误的方法:执行 URL 或重定向请求。

ExecuteUrl

如果想要在自定义错误中执行更多操作(例如发送电子邮件或将错误记录到数据库),则可以执行 URL。 这样,你就可以执行 ASP.NET 页面等动态内容。 下面的示例替换了 404 自定义错误。 现在,每当发生 404 错误时,IIS 都会执行 /404.aspx。

<httpErrors>
<!-- default custom error for 401 errors -->
<!-- <error statusCode="404" prefixLanguageFilePath="c:\inetpub\custerr" path="404.htm" />-->

<!-- ExecuteURL replaces default file response mode -->
<error statusCode="404" path=/404.aspx" responseMode="ExecuteURL"/>        
<error statusCode="403" prefixLanguageFilePath="c:\inetpub\custerr" path="403.htm" />
<error statusCode="404" prefixLanguageFilePath="c:\inetpub\custerr" path="404.htm" />
<error statusCode="405" prefixLanguageFilePath="c:\inetpub\custerr" path="405.htm" />
<error statusCode="406" prefixLanguageFilePath="c:\inetpub\custerr" path="406.htm" />
<error statusCode="412" prefixLanguageFilePath="c:\inetpub\custerr" path="412.htm" />
<error statusCode="500" prefixLanguageFilePath="c:\inetpub\custerr" path="500.htm" />
<error statusCode="501" prefixLanguageFilePath="c:\inetpub\custerr" path="501.htm" />
<error statusCode="502" prefixLanguageFilePath="c:\inetpub\custerr" path="502.htm" />

</httpErrors>

安全注意事项

注意:出于体系结构原因,IIS 只能执行位于同一应用程序池中的 URL。 使用重定向功能在不同的应用程序池中执行“自定义错误”。

当发生特定错误时,IIS 还可以向浏览器返回 302 重定向。 如果你有服务器场,则重定向是不错的选择。 例如,你可以将所有错误都重定向到密切监视的中心位置。

但是存在风险:responseMode=“文件”(默认值)允许指定磁盘上的每个文件。 如果你非常注重安全性,这将不起作用。

可行的方案可能包括仅允许委派 errorMode 设置。 这样,开发人员就能够接收其应用程序的“详细的错误”,即使他使用的是远程客户端。 只需设置 errorMode=“详细”。 下面介绍如何配置此方案:

允许委派 httpErrors 部分:

<section name="httpErrors" overrideModeDefault="Allow" />

其次,转到 applicationHost.config 中的 <httpErrors> 部分并对其进行更改,以便仅委托 errorMode:

<httpErrors lockAllAttributesExcept="errorMode" lockElements="error">
    <error statusCode="404" prefixLanguageFilePath="E:\inetpub\custerr" path="404.htm" />
    <error statusCode="401" prefixLanguageFilePath="E:\inetpub\custerr" path="401.htm" />
    <error statusCode="403" prefixLanguageFilePath="E:\inetpub\custerr" path="403.htm" />
    <error statusCode="405" prefixLanguageFilePath="E:\inetpub\custerr" path="405.htm" />
    <error statusCode="406" prefixLanguageFilePath="E:\inetpub\custerr" path="406.htm" />
    <error statusCode="412" prefixLanguageFilePath="E:\inetpub\custerr" path="412.htm" />
    <error statusCode="500" prefixLanguageFilePath="E:\inetpub\custerr" path="500.htm" />
    <error statusCode="501" prefixLanguageFilePath="E:\inetpub\custerr" path="501.htm" />
    <error statusCode="502" prefixLanguageFilePath="E:\inetpub\custerr" path="502.htm" />
</httpErrors>

总结

“自定义错误”和“详细的错误”是强大的 IIS 功能。 它们可帮助你排查问题,而不会损害 IIS 服务器的安全性。 许多配置选项可帮助你自定义定制用户体验。 最重要的是:尝试使用它是很有趣的。

另请参阅