HTTP 407(需要代理身份验证)

时间:2013-02-01 07:19:20

标签: c# http authentication httpwebrequest

我有一些关于HTTP身份验证的基本问题

1)客户端如何了解HTTP的服务器身份验证类型(Basic / Digest / NTLM)?
这可以在HTTP Server端配置吗?

  

我的答案:服务器将设置它必须与客户端执行的身份验证类型。   因此,我们的客户端API(在C#HttpWebRequest API中)将自动处理它。   最好使用Wireshrk并应用HTTP过滤器;您将在Internet协议层获得源IP和目标IP。并且传输控制协议的src和dest端口以及http层的身份验证类型。

2)如果我在客户端和服务器之间放置squid linux proxy;是否有任何需要从我的客户端代码应该知道代理的身份验证类型?或身份验证类型仅与最终HTTP服务器相关?

  

我的回答:如果squid代理放在客户端和服务器之间;它不会使用HTTP身份验证。它可能使用a)DB:使用SQL数据库b)LDAP:使用轻量级目录访问协议。 c)RADIUS:使用RADIUS服务器进行登录验证。等等..   因此,我们必须在HTTP标头中提及代理身份验证凭据。

3)使用WireShark发现浏览器到服务器有三个请求来满足单个请求。

  

a)浏览器发送没有任何身份验证凭据的请求;所以服务器响应401以及relam和nonce。

WWW-Authenticate: Digest realm="realm", qop="auth", nonce="MTM1OTYyMzkyNDU4MzpiOWM0OWY0NmMzMzZlMThkMDJhMzRhYmU5NjgwNjkxYQ=="\r\n <BR>
  

b)第二次浏览器发送带凭证,relam,nonce,cnonce的请求;但仍然服务器回复401;

WWW-Authenticate: Digest realm="realm", qop="auth", nonce="MTM1OTYyMzk0OTAyMTo3Njk3MDNhZTllZDQyYzQ5MGUxYzI5MWY2MGU5ZDg0Yw==", stale="true"\r\n
  

c)第三次浏览器使用相同的凭据,relam,nonce,cnonce发送相同的请求。这次服务器发送200 ok。

我的问题是第二次和第三次浏览器发送相同的请求;为什么服务器第二次失败并在第三次成功。这是因为我的服务器实现? (我正在使用带有SPRING Security过滤器的REST Java服务器)。

我有C#HTTP客户端;

  

虽然设置了System.Net.NetworkCredentials,但在没有凭据的情况下第一次发送HttpWebRequest;所以clinet得到407与relam和nonce。
第二次HttpWebRequest成功。此客户端没有第三个请求,例如浏览器。

为什么浏览器和C#客户端之间存在差异?

  

我的回答:我仍然不知道这里发生了什么:Q3。

4)现在我面临的真正问题是当我们的客户端和HTTP服务器之间出现SQUID LINUX PROXY时,浏览器执行了相同的三个请求身份验证并成功完成。但是,C#HttpWebRequest在第二个请求时失败(401)并到达缓存(异常){}块并且第三次没有尝试。

当你介绍PROXY SERVER时,有没有人可以请大家澄清一下如何在C#客户端解决这个问题?

下面的代码正在执行GET请求。

  HttpWebRequest request = WebRequest.Create("url") as HttpWebRequest;
  request.Credentials = new NetworkCredential(loginUserName, password);
  WebResponse response = request.GetResponse(); 

请注意,我们的代理请求是通过TCP协议发送的,而不是HTTP协议。然后从PROXY到SERVER与HTTP协议进行通信。 但来自Proxy的HTTP请求在HTTP标头X-Forwarded-For中有关于我们的客户端IP的信息。

以下是可能的解决方案

这些解决方案仅在您的代理需要任何身份验证时才需要,否则请忽略它。

解决方案1:为我工作

request.Proxy.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;

解决方案2:

  IWebProxy proxy = WebRequest.GetSystemWebProxy();
  proxy.Credentials = new NetworkCredential(UserName, UserPassword, UserDomain);
  request.Proxy = proxy;

Martin提供的解决方案3:

  var proxy = new WebProxy ("http://localhost:3128/");
  proxy.Credentials = new NetworkCredential (UserName, UserPassword, UserDomain);
  request.Proxy = proxy;

了解有关代理身份验证的详情 http://wiki.squid-cache.org/Features/Authentication

1 个答案:

答案 0 :(得分:4)

这是一项挑战/响应协议。通常,客户端在没有任何身份验证标头的情况下发出初始请求(您可以设置request.PreAuthenticate = true以使用第一个请求发送凭据)。

然后,服务器响应它支持的身份验证方法列表。

如果用户没有使用CredentialsCache显式指定身份验证方法,则运行时将尝试所有方法,从最强到最弱。某些协议(例如NTLM)需要从客户端到服务器的多个请求。从理论上讲,Digest应该只使用一个,不知道它为什么要两次发送请求。

关于您的代理问题,有两种不同的身份验证:

  1. 目标网络服务器的身份验证,代理只是传递了这个,而您的客户端不需要任何特殊代码。
  2. 除此之外,代理本身也可能需要身份验证 - 这可能与目标Web服务器不同。
  3. 您可以使用

    指定这些内容
    var proxy = new WebProxy ("http://localhost:3128/");
    proxy.Credentials = new NetworkCredential ("username", "password");
    

    然后

    WebRequest.DefaultWebProxy = proxy;
    

    request.Proxy = proxy;
    

    如果您的代理服务器不使用任何身份验证,请不要在WebProxy上设置任何凭据。

    如果在使用代理服务器时无法使用身份验证,请查看使用Wireshark在三方(Web服务器,代理,客户端)之间发送的实际请求。