根据请求在.net HttpWebRequest上设置SecurityProtocol(Ssl3或TLS)

Ric*_*ich 32 .net httpwebrequest

我的应用程序(.net 3.5 sp1)使用HttpWebRequest与不同的端点进行通信,有时它使用HTTPS,其中每个托管服务器可能具有不同的安全协议要求,例如TLS或SSL3或其中之一.

通常,服务器可以很好地和愉快地协商/回退SecurityProtocol使用TLS或SSL3,但有些则没有,当.net被设置为TLS或SSL3(我认为默认)那些仅支持SSL3的服务器会导致.net抛出发送错误.

据我所知,.net为ServicePointManager对象提供了一个属性SecurityProtocol,可以将其设置为TLS,SSL3或两者.因此理想情况下,当设置为两个想法是客户端和服务器应该协商使用什么,但如前所述似乎不起作用.

据说你可以设置ServicePointManager.SecurityProtocol = Ssl3但是那些想要使用TLS的端点呢?

我在ServicePointManager和SecurityProtocol中看到的问题是它的静态和应用程序域范围.

那么问题..

我将如何使用不同的SecurityProtocol来使用HttpWebRequest,例如

1)url 1设置为使用TLS | Ssl3(谈判)

2)url 2设置为Ssl3(仅限Ssl3)

fer*_*oze 16

不幸的是,它看起来不像你可以为每个服务点定制.我建议您在MS Connect网站上为此区域提交功能请求.

作为一种肮脏的解决方法,您可以尝试在新的appdomain中执行需要不同安全协议的站点.静态实例是每个appdomain,因此应该为您提供所需的隔离.

  • MS Connect请求https://connect.microsoft.com/VisualStudio/feedback/details/605185/cant-set-the-security-protocol-per-servicepoint状态为"无法修复" (5认同)
  • @MichaelFreidgeim如果看看现在,微软已回复解释它将在> Net Framework 4.7.1中修复 - *"在即将发布的.NET Framework 4.7.1中,我们为HttpClientHandler类添加了新属性,用于System.Net.HttpClient.这是用于HTTP请求而不是HttpWebRequest的首选API.添加了这些新属性以匹配已经在HttpClientHandler上具有更新属性的.NET Core 2.0版本."* (2认同)

k01*_*mb0 13

我遇到了同样的问题并编写了代理类,它在localhost上打开端口并将所有流量转发到指定的host:port.

所以连接就是这样的

[你的代码] --- HTTP ---> [localhost:port上的代理] --- HTTPS ---> [网站]

事实上,它可以用于将任何协议包装到SSL/TLS中,而不仅仅是HTTP

using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;

namespace System
{
    class sslProxy : IDisposable
    {
        readonly string host;
        readonly int port;
        readonly TcpListener listener;
        readonly SslProtocols sslProtocols;
        bool disposed;
        static readonly X509CertificateCollection sertCol = new X509CertificateCollection();
        public sslProxy(string url, SslProtocols protocols)
        {
            var uri = new Uri(url);
            host = uri.Host;
            port = uri.Port;
            sslProtocols = protocols;
            listener = new TcpListener(IPAddress.Loopback, 0);
            listener.Start();
            listener.BeginAcceptTcpClient(onAcceptTcpClient, null);
            Proxy = new WebProxy("localhost", (listener.LocalEndpoint as IPEndPoint).Port);
        }
        public WebProxy Proxy
        {
            get;
            private set;
        }
        class stBuf
        {
            public TcpClient tcs;
            public TcpClient tcd;
            public Stream sts;
            public Stream std;
            public byte[] buf;
            public stBuf dup;
        }
        void onAcceptTcpClient(IAsyncResult ar)
        {
            if (disposed) return;
            var tcl = listener.EndAcceptTcpClient(ar);
            TcpClient tcr = null;
            try
            {
                listener.BeginAcceptTcpClient(onAcceptTcpClient, null);
                var nsl = tcl.GetStream();

                tcr = new TcpClient(host, port);
                Stream nsr = tcr.GetStream();
                if (sslProtocols != SslProtocols.None)
                {
                    var sss = new SslStream(nsr, true);
                    sss.AuthenticateAsClient(host, sertCol, sslProtocols, false);
                    nsr = sss;
                } // if

                var sts = new stBuf() { tcs = tcl, sts = nsl, tcd = tcr, std = nsr, buf = new byte[tcl.ReceiveBufferSize] };
                var std = new stBuf() { tcs = tcr, sts = nsr, tcd = tcl, std = nsl, buf = new byte[tcr.ReceiveBufferSize] };
                sts.dup = std;
                std.dup = sts;

                nsl.BeginRead(sts.buf, 0, sts.buf.Length, onReceive, sts);
                nsr.BeginRead(std.buf, 0, std.buf.Length, onReceive, std);
            } // try
            catch
            {
                tcl.Close();
                if (tcr != null) tcr.Close();
            } // catch
        }
        void close(stBuf st)
        {
            var dup = st.dup;
            if (dup != null)
            {
                dup.dup = st.dup = null;
                st.sts.Dispose();
                st.std.Dispose();
            } // if
        }
        void onReceive(IAsyncResult ar)
        {
            var st = ar.AsyncState as stBuf;
            try
            {
                if (!(st.dup != null && st.tcs.Connected && st.sts.CanRead && !disposed)) { close(st); return; };
                var n = st.sts.EndRead(ar);
                if (!(n > 0 && st.tcd.Connected && st.std.CanWrite)) { close(st); return; };
                st.std.Write(st.buf, 0, n);
                if (!(st.tcs.Connected && st.tcd.Connected && st.sts.CanRead && st.std.CanWrite)) { close(st); return; };
                st.sts.BeginRead(st.buf, 0, st.buf.Length, onReceive, st);
            } // try
            catch
            {
                close(st);
            } // catch
        }
        public void Dispose()
        {
            if (!disposed)
            {
                disposed = true;
                listener.Stop();
            } // if
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例

// create proxy once and keep it
// note you have to mention :443 port (https default)
// ssl protocols to use (enum can use | or + to have many)
var p = new sslProxy("http://www.google.com:443", SslProtocols.Tls);
// using our connections
for (int i=0; i<5; i++)
{
    // url here goes without https just http
    var rq = HttpWebRequest.CreateHttp("http://www.google.com/") as HttpWebRequest;
    // specify that we are connecting via proxy
    rq.Proxy = p.Proxy;
    var rs = rq.GetResponse() as HttpWebResponse;
    var r = new StreamReader(rs.GetResponseStream()).ReadToEnd();
    rs.Dispose();
} // for
// just dispose proxy once done
p.Dispose();
Run Code Online (Sandbox Code Playgroud)

  • 为什么没有得到更多的投票或没有作为答案检查?我还没试过这个,但@ k010mb0你会考虑这个答案吗?这在高性能Web应用程序设置中如何执行? (2认同)

j.v*_*.v. 10

在我们的一些供应商停止对ssl3的支持而其他供应商专门使用它之后,我们的系统中出现了许多问题,这些问题可以通过这个问题的功能来解决.但六年后,我们仍然没有内置机制来实现这一目标.我们的解决方法是明确定义支持所有方案的安全协议,如下所示:

    System.Net.ServicePointManager.SecurityProtocol = 
    System.Net.SecurityProtocolType.Ssl3 
    | System.Net.SecurityProtocolType.Tls12 
    | SecurityProtocolType.Tls11 
    | SecurityProtocolType.Tls;
Run Code Online (Sandbox Code Playgroud)