【问题标题】:Connect over company proxy with user name使用用户名通过公司代理连接
【发布时间】:2021-06-25 14:16:46
【问题描述】:

我正在尝试连接到外部 IP 地址,但我在公司防火墙后面,所以我需要通过代理连接。

我用 curl 运行测试:

curl -v https://IP_ADDRESS_OF_EXTERNAL_CLIENT:6125 -x http://MyComparyProxyAddress.com:8080 -U MYUSERNAME:MYPASSWORD

但我无法在 C# 中复制上述 cUrl 命令:

private static Socket CreateTunnelThruProxy(string destIP, int destPort)
        {
            string destUriWithPort = $"{destIP}:{destPort}";
            UriBuilder uriBuilder = new UriBuilder(destUriWithPort);
            Uri destUri = uriBuilder.Uri;

            var proxy = new WebProxy("http://MyComparyProxyAddress.com", 8080);
            proxy.UseDefaultCredentials = false;
            proxy.Credentials = new NetworkCredential("MYUSERNAME", "MYPASSWORD");
            WebRequest.DefaultWebProxy = proxy;

            IWebProxy webProxy = WebRequest.DefaultWebProxy;

            try
            {
                if (webProxy.IsBypassed(destUri))
                    return null;
            }
            catch (PlatformNotSupportedException)
            {
                // .NET Core doesn't support IWebProxy.IsBypassed
                // (because .NET Core doesn't have access to Windows-specific services, of course)
                return null;
            }

            Uri proxyUri = webProxy.GetProxy(destUri);
            if (proxyUri == null)
                return null;

            IPAddress[] proxyEntry = Dns.GetHostAddresses(proxyUri.Host);
            int iPort = proxyUri.Port;
            IPAddress address = proxyEntry.First(a => a.AddressFamily == AddressFamily.InterNetwork);
            IPEndPoint proxyEndPoint = new IPEndPoint(address, iPort);
            Socket socketThruProxy = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socketThruProxy.Connect(proxyEndPoint);

            string proxyMsg = $"CONNECT {destIP}:{destPort} HTTP/1.1 \n\n";
            byte[] buffer = Encoding.ASCII.GetBytes(proxyMsg);
            byte[] buffer12 = new byte[50000];
            socketThruProxy.Send(buffer, buffer.Length, 0);
            int msg = socketThruProxy.Receive(buffer12, 50000, 0);
            string data;
            data = Encoding.ASCII.GetString(buffer12);
            int index = data.IndexOf("200");

            if (index < 0)
                throw new ApplicationException(
                    $"Connection failed to {destUriWithPort} through proxy server {proxyUri.ToString()}.");

            return socketThruProxy;
        }

我不断从我的公司代理处获得以下信息:

HTTP/1.1 407 Proxy Authentication Required
Proxy-Authenticate: NEGOTIATE
Proxy-Authenticate: NTLM
Proxy-Authenticate: BASIC realm="ztb"
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/html; charset=utf-8
Proxy-Connection: close
Connection: close
Content-Length: 797

<HTML><HEAD>
<TITLE>Access Denied</TITLE>
</HEAD>
<BODY>
<body bgcolor="#FFFFEA">
<blockquote>
<TABLE border=0 cellPadding=1 width="80%">
<TR><TD>
<FONT face="Verdana">
<big>Access Denied (authentication_failed)</big>
<BR>
<BR>
</FONT>
</TD></TR>
<TR><TD>
<FONT face="Verdana">
Your credentials could not be authenticated: "Credentials are missing.". You will not be permitted access until your credentials can be verified.
</FONT>
</TD></TR>
<TR><TD>
<FONT face="Verdana">
This is typically caused by an incorrect username and/or password, but could also be caused by network problems.
</FONT>
</TD></TR>
<TR><TD>
<FONT face="Verdana" SIZE=2>
<BR>
For assistance, contact your Tech Desk . PXFFM25
</FONT>
</TD></TR>
</TABLE>
</blockquote>
</FONT>
</BODY></HTML>

我可以清楚地看到 webProxy 对象包含我设置的凭据,与使用 cUrl 的凭据相同。

我在尝试简单调用时也遇到了同样的错误:

IWebProxy webProxy = WebRequest.GetSystemWebProxy();

而不是手动设置凭据,如上面的代码 sn-p。所以看起来我的凭据没有被考虑在内......

有什么想法吗?

【问题讨论】:

  • 您需要成为管理员吗?在 VS 中运行你不是管理员,除非你通过右键单击快捷方式启动 VS 并选择以管理员身份运行。
  • 我没有在管理员模式下启动 Visual Studio,因为这对我来说是被阻止的。但是,这不是必需的,因为“cUrl”可以正常工作。但无论如何,我尝试以管理员身份运行二进制文件,但我不断收到同样的异常。
  • 我会尝试使用 HTTPS 而不是 HTTP。请参阅以下 -x 选项:curl.se/docs/manpage.html 也尝试使用默认凭据:CredentialCache.DefaultCredentials;
  • 我尝试了 https 代理,没有运气。尝试使用 CredentialCache.DefaultCredentials 时,我从代理中得到完全相同的异常。这意味着代理不考虑我手动覆盖凭据的尝试(根据上面的代码)。
  • 出错需要多长时间?如果找不到代理,通常代码会在报告代理错误之前等待 30 秒。它认为您将进入错误的域。从 cmd.exe >IPConfig/All 这将为您提供网络适配器 (IP) 和掩码的数量。也尝试使用 HTTP 而不是 HTTPS。您在公司防火墙内,可能不需要保护连接。 Curl 可能会回到 HTTP。可能发生的是 Curl 使用 IPV4 和 c# 使用 IPV6。 IPV4 说更喜欢吗?

标签: c# .net proxy webrequest webproxy


【解决方案1】:

我之前尝试过这个场景,它通过创建一个继承 IWebProxy 的自定义代理类与我一起工作

public class MyProxy : IWebProxy
    {
        public ICredentials Credentials
        {
            get { return new NetworkCredential("your username","your password"); }
            set { }
        }

        public Uri GetProxy(Uri destination)
        {
            return new Uri("http://MyComparyProxyAddress.com:8080");
        }

        public bool IsBypassed(Uri host)
        {
            return false;
        }
    } 

并在应用配置文件中将这部分添加到配置节点中

  <system.net>
    <defaultProxy enabled="true" useDefaultCredentials="false">
      <module type="yournamespace.MyProxy, your assembly name" />
    </defaultProxy>
  </system.net>

【讨论】:

  • 不幸的是,这种封装没有起作用,我一直收到同样的异常。请注意,我发送了 Socket 消息:socketThruProxy.Send(buffer, buffer.Length, 0);其中 buffer=$"CONNECT {destIP}:{destPort} HTTP/1.1 \n\n"
  • @Jack system.net 配置文件中的配置将适用于您的应用程序作为客户端建立的所有网络连接,无论您是通过套接字、Web 客户端连接还是连接到 Web 服务。但是,我会尝试在我的最后模拟这个案例,如果它对我有用,我会更新答案。祝你好运
【解决方案2】:

如果允许的话,我会将其添加为评论,但添加域有帮助吗?过去,当我进行身份验证时,我必须确保域是正确的。每Network Credential docs

有一个构造函数接受域,或者您可以将其设置为属性。

【讨论】:

    【解决方案3】:

    不要尝试在您的代码中修复此问题。 使用https://github.com/genotrance/px 之类的本地代理向企业代理提供您的用户凭据。 否则有一天你会在你的源代码管理中找到一个开发者密码。

    【讨论】:

      【解决方案4】:

      我的一个项目遇到了这个问题,该公司使用防火墙(确切地说是Barracuda's firewall)。我尝试设置 WebProxy 并设置机器代理,但没有成功。

      我是这样解决的:

      我已要求安全团队将 IP 以及将用于服务的端口列入白名单。所以任何传出或传入的连接都不会被阻止。然后,从应用程序中,我在web.config 中设置了代理,如下所示:

      <system.net>
          <defaultProxy>
              <proxy usesystemdefault="False" proxyaddress="http://proxy_ip" bypassonlocal="False" />
          </defaultProxy>
      </system.net>
      

      此外,在运行应用程序的服务器上设置了相同的代理。

      这使事情按预期工作。

      一周左右后,服务突然停止。当我检查与Fiddler 的连接时,它显示API 被重定向到另一台服务器(不同的IP),防火墙阻止了它。因此,我要求安全团队也将其列入白名单,该服务又恢复了运行。

      【讨论】:

        【解决方案5】:

        这可以通过以下方式完成:

         if (IsProxyProvided(settings))
                    {
                        IPAddress[] proxyEntry = Dns.GetHostAddresses(settings.ProxyHost);
                        IPAddress address = proxyEntry.First(a => a.AddressFamily == AddressFamily.InterNetwork);
                        IPEndPoint proxyEndPoint = new IPEndPoint(address, settings.ProxyPort);
                        socket.Connect(proxyEndPoint);
        
                        if (AreProxyCredntialsProvided(settings))
                        {
                            var basicAuthBase64 = Convert.ToBase64String(
                                Encoding.GetEncoding("ISO-8859-1").GetBytes($"{settings.ProxyUserName}:{settings.ProxyUserNamePassword}"));
                            var proxyMessage = $"Proxy-Authorization: {string.Format("Basic {0}", basicAuthBase64)} \r\n";
                            var keepAlive = "Connection: keep-alive\r\n";
                            var request = $"CONNECT {endpoint.Address}:{endpoint.Port} HTTP/1.1 \r\n" + proxyMessage + keepAlive + "\r\n";
                            byte[] buffer = Encoding.ASCII.GetBytes(request);
                            socket.Send(buffer, buffer.Length, 0);
                        }
                    }
        

        感谢有类似问题的 Victor Victor Stone here

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-05-30
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多