Установите SecurityProtocol (Ssl3 или TLS) в .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, заключается в том, что ее статический и, следовательно, домен приложения широко.
Итак, на вопрос..
как я могу использовать HttpWebRequest с другим SecurityProtocol, например.
1) url 1 установлен для использования TLS | Ssl3 (переговоры)
2) url 2 установлен в Ssl3 (только Ssl3)
Ответы
Ответ 1
К сожалению, это не похоже на то, что вы можете настроить это для каждой точки обслуживания. Я предлагаю вам подать запрос на функцию на веб-сайте MS Connect для этой области.
Как грязное обходное решение, вы можете попробовать выполнить сайты, для которых требуется другой протокол безопасности в новом приложении. Статические экземпляры для каждого приложения, поэтому это должно дать вам необходимую вам изоляцию.
Ответ 2
У меня была такая же проблема и я написал прокси-класс, который открывает порт на localhost и пересылает весь трафик на указанный хост: порт.
поэтому соединение будет выглядеть следующим образом:
[ваш код] --- HTTP --- > [прокси на localhost: порт] --- 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
}
}
}
Пример использования
// 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();
Ответ 3
В соответствии с этим ответом параметр SecurityProtocol фактически является per-AppDomain, поэтому вы могли бы, если бы решились заставить его работать, создать отдельные AppDomains для отдельных настроек, и сортируйте свои запросы через.
Не совсем "аккуратное" решение, но может просто сделать то, что вам нужно, не прибегая к сторонним библиотекам.
Ответ 4
После того, как некоторые из наших поставщиков прекратили поддержку ssl3, а другие используют его исключительно, в нашей системе появилось много проблем, которые могут быть решены с функциональностью из этого вопроса. Но через шесть лет у нас все еще нет встроенного механизма для достижения этого. Наше обходное решение заключается в явном определении протокола безопасности, который будет поддерживать все сценарии, например:
System.Net.ServicePointManager.SecurityProtocol =
System.Net.SecurityProtocolType.Ssl3
| System.Net.SecurityProtocolType.Tls12
| SecurityProtocolType.Tls11
| SecurityProtocolType.Tls;
Ответ 5
Вы можете достичь этого с помощью этого кода, чтобы закрыть все базовые соединения и принудительно установить новое рукопожатие.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
...
...
...
request.ServicePoint.CloseConnectionGroup(request.ConnectionGroupName);
Ответ 6
Вы можете сделать "служебный класс" HttpWebRequest со статическим утилитным методом для создания HttpWebRequests. В статическом методе утилиты используйте оператор С# lock вокруг настройки ServicePointManager.SecurityProtocol и создания определенного HttpWebRequest. Оператор блокировки запрещает другим потокам из одного и того же AppDomain выполнять один и тот же код одновременно, поэтому только что установленный протокол TLS не будет изменен до тех пор, пока не будет выполнен весь блок блокировки (= критический раздел).
Но, учитывая, что для действительно высокопроизводительных приложений (чрезвычайно высокопроизводительных!) этот аспект может иметь отрицательное влияние на производительность.
Ответ 7
Задайте все это. В моем приложении это работа для разных протоколов безопасности.
System.Net.ServicePointManager.SecurityProtocol =
System.Net.SecurityProtocolType.Ssl3
| System.Net.SecurityProtocolType.Tls12
| SecurityProtocolType.Tls11
| SecurityProtocolType.Tls;