Http 401错误重现实验及解决办法

根据http协议对状态码的定义401代表未经授权的访问。在IIS中在401的基础上定义了一系列的子状态码来代表各种不同情况下未经授权访问的具体原因。

401.1 - Logon failed. -登陆失败

401.2 - Logon failed due to server configuration.-基于服务器配置的登陆失败

401.3 - Unauthorized due to ACL on resource.-资源访问控制列表返回未授权

401.4 - Authorization failed by filter.-服务器filter返回未授权

401.5 - Authorization failed by ISAPI/CGI application.-服务器ISAPI/CGI返回未授权

 

这篇文章中主要来介绍各种常见401错误的重现方法相应的解决方案。在这之前首先介绍一下对于401问题的定位方式,即如何知道发生了401错误。


401问题的定位方式

对于401问题的定位我们要区分我们是在客户端还是在服务器端访问页面,因为服务器对于错误返回消息的配置不同使我们在浏览器中看到的结果大相径庭。


客户端对于401问题的定位

在客户端我们遇到401问题时经常会见到的页面如下,这是一个IIS 7及以上版本的默认401错误页面。

Http 401错误重现实验及解决办法_第1张图片

服务器也可以配置使用不同的错误页面来呈现这个问题。所以更为精确的定位方式我们还是要参考服务器返回的状态码。

IE中打开F12开发者工具,切换到network选项卡,然后点start capturing。访问该网页,抓取的network追踪记录中就可以看到401的返回码。

Http 401错误重现实验及解决办法_第2张图片

服务端对于401问题的定位

在服务器端访问出错页面的结果如下,一般默认配置情况下服务器会显示详细的错误信息。

Http 401错误重现实验及解决办法_第3张图片

另外我们也可以通过查看IIS日志来确定详细的出错码。

打开IIS - Loggingfeature注意需要确定SelectFields中选中了Protocal StatusProtocal Substatus (默认情况下是选中的)

Http 401错误重现实验及解决办法_第4张图片

然后到日志记录中查找相应的请求记录,从而确定返回状态码与子码分别是什么。

 

#Software:Microsoft Internet Information Services 8.0

#Version:1.0

#Date:2012-10-05 04:34:24

#Fields:date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ipcs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken

2012-10-0504:34:24 ::1 GET /iisstart.htm - 80 - ::1Mozilla/5.0+(compatible;+MSIE+10.0;+Windows+NT+6.2;+WOW64;+Trident/6.0) -401 2 5 753


401.1 - Logon Failed

问题重现

401.1问题一般是因为用户名和密码无法在服务器通过认证导致。要重现这个问题可以在服务器禁用匿名访问方式。启用basic认证方式。

Http 401错误重现实验及解决办法_第5张图片

再次访问页面,就会弹出如下需要输入用户名和密码的对话框。

Http 401错误重现实验及解决办法_第6张图片

如果三次输入的用户名和密码出错的话,你就会得到这样一个页面

Http 401错误重现实验及解决办法_第7张图片

如果是服务器端详细的信息是这样的

Http 401错误重现实验及解决办法_第8张图片

解决方案

这种问题一般发生的原因就是用户名和密码不正确。可以尝试重置用户密码或通过另外一个用户登陆来定位是否是用户名密码的问题。

另外还有一种较为常见的在服务器的应用程序池运行在一个本地或者域账户的情况下,因为kerberos认证失败而导致401.1错误。这种问题的解决办法可以参照这里


401.2 - Logon failed due to server configuration

问题重现

401.2问题一般是因为服务器配置原因导致的,比如最常见的服务器启用了基于401Challenge的认证方式,那么客户端尝试发送匿名请求给服务器,服务器就会返回401 Challenge给客户端,客户端受到这个回复之后就会弹出认证对话框,如上面重现401.1问题时的认证对话框。而这个401Challenge请求在服务器日志里面会记录成401.2

所以当在日志中发现下面这种401.2错误的时候不用担心,因为可以看到用户名为空的请求返回了401.2,之后又有带了用户名的请求返回了200(请求成功)

2012-10-0507:26:40 ::1 GET /iisstart.htm - 80 - ::1Mozilla/5.0+(compatible;+MSIE+10.0;+Windows+NT+6.2;+WOW64;+Trident/6.0) -401 2 5 7

2012-10-0507:27:08 ::1 GET /iisstart.htm - 80 - ::1Mozilla/5.0+(compatible;+MSIE+10.0;+Windows+NT+6.2;+WOW64;+Trident/6.0) -401 2 5 8

2012-10-0507:27:26 ::1 GET /iisstart.htm - 80domain\user1 ::1Mozilla/5.0+(compatible;+MSIE+10.0;+Windows+NT+6.2;+WOW64;+Trident/6.0) - 200 0 0 409

另外一种401.2的重现方式非常简单,是把所有的认证方式全部禁用,再次访问网页就会返回401.2错误消息。在第一节问题一般定位方式截图中显示的401.2错误就是把所有的认证方式禁用得到的。

第三种方式比较特殊,我们可以通过服务器端配置authorization rule来禁止或者允许特定的用户访问。为了重现问题我们禁用所有的用户。

Http 401错误重现实验及解决办法_第9张图片


访问网页之后发现返回401.2错误,在服务器详细错误中在这里我们要关注的一点是Module中显示的信息,这里我们可以看到是UrlAuthorizationModule,而不是前面禁用了所有认证方式的IISWeb Core,这就告诉我们出错的地方在于配置的的Authorization Rules

Http 401错误重现实验及解决办法_第10张图片

解决方案

第一种情况属于正常现象,不是问题

第二种情况即没有启用任何认证方式,只需要在IIS Manager里面启用需要的认证方式即可。

第三种情况即被Authorization Rule阻挡,则需要分析这个authorization rule是否是否必须来决定对他的更改。

还有第四种情况,就是在配置文件中指定了认证方式但是相应的认证模块没有安装。这种情况多发生在系统迁移的过程中。解决方案就是把相应的认证模块安装上。


401.3 - Unauthorized due to ACL on resource

问题重现

401.3问题是最明显的一个,即没有权限访问文件(),要重现这个问题我们可以将要访问的文件的安全性设置为拒绝任何人访问。然后请求该文件就会得到以下出错信息。

Http 401错误重现实验及解决办法_第11张图片


在这里需要关注的错误显示的Logon User,这样可以知道你正在以什么身份访问文件。

 

解决方案

调试401.3需要知道两件事,

第一是什么资源组织了访问,问题出在上级文件夹还是文件本身。

第二是我们以什么样的身份访问资源的时候被阻止了。

 

调试这个问题最好的工具是Process Monitor。打开Process Monitor过滤w3wp进程对文件的访问。就可以看到access deny被记录下来。同时还有访问身份信息。这样我们就可以在文件系统做相应的更改来解决问题。

Http 401错误重现实验及解决办法_第12张图片


401.4 - Authorization failed by filter

问题重现

401.4问题重现比起前面要更加费些周折,因为这个错误的意思是自定义filter返回了拒绝访问的错误。所以我们要先创建一个自定义filter

这里值得注意的是在IIS6上只能创建自定义ISAPI Filter来处理进入的各种请求,创建ISAPI Extension来处理特定的请求。而这两种扩展方式在IIS7及以上的版本不再被推荐使用,取而代之的是创建Http ModuleHttpHandler来扩展IIS的功能,而且支持托管和非托管两种模式,开发和调试都更加方便。

 

为了更形象的重现这个问题,我们还是采用ISAPI Filter的方式。创建ISAPI Filter需要两个文件。

401-4-Filter.def

LIBRARY      401-4-Filter

;DESCRIPTION  'filter to return 401.4'

EXPORTS
    HttpFilterProc
    GetFilterVersion
401-4-Filter.C
#include 
#include 

#define DEFAULT_BUFFER_SIZE         1024
#define MAX_BUFFER_SIZE             4096

DWORD
OnPreprocHeaders(
    IN HTTP_FILTER_CONTEXT *            pfc,
    IN HTTP_FILTER_PREPROC_HEADERS *    pPPH
);

BOOL
WINAPI
GetFilterVersion(
    HTTP_FILTER_VERSION *           pVer
    )
{
    pVer->dwFilterVersion = HTTP_FILTER_REVISION;
    lstrcpyn( pVer->lpszFilterDesc,
             "Filter to return 401.4 error",
             SF_MAX_FILTER_DESC_LEN );
    pVer->dwFlags =
        SF_NOTIFY_ORDER_HIGH |
        SF_NOTIFY_PREPROC_HEADERS
        ;

    return TRUE;
}

DWORD
WINAPI
HttpFilterProc(
    IN HTTP_FILTER_CONTEXT *        pfc,
    DWORD                           dwNotificationType,
    LPVOID                          pvNotification
    )
{
    switch ( dwNotificationType )
    {
    case SF_NOTIFY_PREPROC_HEADERS:
        return OnPreprocHeaders(
            pfc,
            (HTTP_FILTER_PREPROC_HEADERS *) pvNotification );
    }

    return SF_STATUS_REQ_NEXT_NOTIFICATION;
}

DWORD
OnPreprocHeaders(
    HTTP_FILTER_CONTEXT *           pfc,
    HTTP_FILTER_PREPROC_HEADERS *   pPPH
)
{
    SetLastError( ERROR_ACCESS_DENIED  );
    return SF_STATUS_REQ_ERROR;
}

将其编译成与application pool CPU架构(x86|x64)相同的classlibrary。然后通过IIS Manager功能视图中ISAPI Filter中加入编译产生的Dll。之后请求页面就会得到如下返回。

Http 401错误重现实验及解决办法_第13张图片

解决方案

可以看到详细信息中并没有显示出出问题的模块,这里就需要我们通过一定的调试手段来定位这个出错的模块在哪里。比较方便的方式是通过failed request tracing追踪请求,找到出错的模块。

详细的方法可以参考这里

http://support.microsoft.com/kb/942079/zh-cn


401.5 - Authorization failed by ISAPI/CGI application

问题重现

401.5问题的出现原因可能源于以下几个方面阻止了请求。

  • 自定义的ISAPIextension
  • CGI程序
  • ASP页面
  • 自定义handler

这里通过一个managedhttp handler来重现这个问题,将以下代码放在网站根目录下App_Code文件夹,然后在IISManager功能视图里选在Handler Mapping,添加Managed Handler,选择一个对应的请求路径,我们这里用它来处理所有*.aa的文件请求,之后在网站里面加入一个test.aa文件,通过浏览器发送请求。

using System.Web;

namespace 4015Handler
{
    public class 4015Handler: IHttpHandler
    {
        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
            context.Response.StatusCode = 401;
            context.Response.SubStatusCode = 5;
            context.Response.End();
        }
    }
}

就会得到这样的结果。

Http 401错误重现实验及解决办法_第14张图片

解决方案

对于这个问题的定位方式与401.4一样,可以通过failedrequest tracing来跟踪消息,找到出错的模块。

 

详细方法如下

http://support.microsoft.com/kb/942078/zh-cn


你可能感兴趣的:(IIS/ASP.NET,程序调试)