程序问答   发布时间:2022-06-02  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了协商了哪个TLS版本?大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决协商了哪个TLS版本??

开发过程中遇到协商了哪个TLS版本?的问题如何解决?下面主要结合日常开发的经验,给出你关于协商了哪个TLS版本?的解决方法建议,希望对你解决协商了哪个TLS版本?有所启发或帮助;

您可以使用反射来获取Tlsstream->SslState->SslProtocol属性值。 这些信息可以从双方返回的流中提取httpWebRequest.GetRequestStream()httpWebRequest.GetResponseStream()

ExtractSslProtocol()还处理压缩GzipStream或者DeflateStream当被返回WebRequestAutomaticDecompression被激活。

验证将在中进行ServerCertificateValIDationCallback,当使用初始化请求时会调用。request.GetRequestStream()

: 包含在.Net Framework 4.8+和.Net Core中3.0+

using System.IO.Compression;
using System.Net;
using System.Net.Security;
using System.Reflection;
using System.Security.Authentication;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

    //(...)
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | 
                                           SecurityProtocolType.Tls | 
                                           SecurityProtocolType.Tls11 | 
                                           SecurityProtocolType.Tls12 | 
                                           SecurityProtocolType.Tls13;
    ServicePointManager.ServerCertificateValIDationCallback += TlsValIDationCallback;

    Uri requestUri = new Uri("https://somesite.com");
    var request = WebRequest.Createhttp(requestUri);

    request.Method = WebRequestMethods.http.Post;
    request.ServicePoint.Expect100Continue = false;
    request.AllowautoRedirect = true;
    request.cookieContainer = new cookieContainer();

    request.ContentType = "application/x-www-form-urlencoded";
    var postdata = EnCoding.UTF8.GetBytes("Some postdata here");
    request.ContentLength = postdata.Length;

    request.UserAgent = "Mozilla/5.0 (windows NT 6.1; WOW64; TrIDent / 7.0; rv: 11.0) like Gecko";
    request.automaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
    request.headers.Add(httpRequestheader.AcceptEnCoding, "gzip, deflate;q=0.8");
    request.headers.Add(httpRequestheader.CacheControl, "no-cache");

    using (var requestStream = request.GetRequestStream()) {
        //Here the request stream is already valIDated
        SslProtocols sslProtocol = ExtractSslProtocol(requestStream);
        if (sslProtocol < SslProtocols.Tls12)
        {
            // Refuse/close the connection
        }
    }
    //(...)

private SslProtocols ExtractSslProtocol(Stream stream)
{
        if (stream is null) return SslProtocols.None;
        BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
        Stream MetaStream = stream;
        if (stream.GetType().BaseType == typeof(GZipStream)) {
            MetaStream = (stream as GZipStream).BaseStream;
        }
        else if (stream.GetType().BaseType == typeof(DeflateStream)) {
            MetaStream = (stream as DeflateStream).BaseStream;
        }

        var connection = MetaStream.GetType().GetProperty("Connection", bindingFlags).GetValue(MetaStream);
        if (!(bool)connection.GetType().GetProperty("UsingSecureStream", bindingFlags).GetValue(connection)) {
            // Not a https connection
            return SslProtocols.None;
        }
        var tlsstream = connection.GetType().GetProperty("NetworkStream", bindingFlags).GetValue(connection);
        var tlsstate = tlsstream.GetType().GetFIEld("m_Worker", bindingFlags).GetValue(tlsstream);
        return (SslProtocols)tlsstate.GetType().GetProperty("SslProtocol", bindingFlags).GetValue(tlsstate);
}

RemoteCertificateValIDationCallback对所使用的安全协议的一些有用的信息。(请参阅:传输层安全性(TLS)参数(IANA)和RFC 5246)。 使用的安全协议的类型可以提供足够的信息,因为每个协议版本都支持哈希和加密算法的子集。 Tls 1.2引入HMAC-SHA256并弃用IDEADES加密(所有变体在链接的文档中列出)。

在这里,我插入了OIDExtractor,其中列出了正在使用的算法。请注意,TcpClIEnt()和WebRequest()都将到达此处。

private bool TlsValIDationCallback(object sender, X509Certificate CACert, X509Chain CAChain, SslPolicyErrors sslPolicyErrors)
{
    List<OID> oIDExtractor = CAChain
                             .ChainElements
                             .Cast<X509ChainElement>()
                             .Select(x509 => new OID(x509.Certificate.SignatureAlgorithm.Value))
                             .ToList();
    // Inspect the oIDExtractor List

    if (sslPolicyErrors == SslPolicyErrors.None) 
        return true;

    X509Certificate2 certificate = new X509Certificate2(CACert);

    //If you needed/have to pass a certificate, add it here.
    //X509Certificate2 cert = new X509Certificate2(@"[localstorage]/[ca.cert]");
    //CAChain.ChainPolicy.ExtraStore.Add(cert);
    CAChain.Build(certificate);
    foreach (X509ChainStatus CACStatus in CAChain.ChainStatus)
    {
        if ((CACStatus.Status != X509ChainStatusFlags.NoError) &
            (CACStatus.Status != X509ChainStatusFlags.UntrustedRoot))
            return false;
    }
    return true;
}

secur32.dll- > queryContextAttributesW()方法,允许查询一个初始化流的连接安全性上下文。

[Dllimport("secur32.dll", CharSet = CharSet.auto, ExactSpelling=true, SetLastError=false)]
private static extern int queryContextAttributesW(sspIHandle contextHandle,
                                                  [In] ContextAttribute attribute,
                                                  [In] [Out] ref SecPkgContext_ConnectionInfo ConnectionInfo);

从文档中可以看到,此方法返回一个voID* buffer引用SecPkgContext_ConnectionInfo结构的:

//[SuppressUnmanagedCodeSecurity]
private struct SecPkgContext_ConnectionInfo
{
    public SchProtocols DWProtocol;
    public ALG_ID aiCipher;
    public int DWCipherStrength;
    public ALG_ID aiHash;
    public int DWHashStrength;
    public ALG_ID aIExch;
    public int DWExchStrength;
}

所述SchProtocols DWProtocol构件是SslProtocol。

有什么收获。 该Tlsstream.Context.m_SecurityContext._handle引用连接上下文句柄是不公开的。 因此,您只能再次通过反射或通过返回的System.Net.Security.AuthenticatedStream派生类(System.Net.Security.SslStreamSystem.Net.Security.NegotiateStream)来获取它TcpClIEnt.GetStream()

不幸的是,WebRequest / WebResponse返回的Stream不能转换为这些类。仅通过非公共属性和字段引用连接和流类型。

我正在发布汇编的文档,它可能会帮助您找到获取该Context Handle的另一条路径。

声明,结构,枚举器列表位于QueryContextAttributesW(PASTEBIN)中。

身份验证结构

使用Schannel创建安全连接

获取有关Schannel连接的信息

查询Schannel上下文的属性

QueryContextAttributes(Schannel)

Internals.cs

内部结构SSPIHandle {}

内部枚举ContextAttribute {}

在提供的上下文中,有关TcpClient()SslStream用法的一些实现细节。

如果在初始化WebRequest之前需要协议信息,则可以使用TLS连接所需的相同工具在相同的上下文中建立TcpClIEnt()连接。即,ServicePointManager.SecurityProtocol定义支持的协议和ServicePointManager.ServerCertificateValidationCallback验证服务器证书。

TcpClIEnt()和WebRequest都可以使用以下设置: -启用所有协议,并让Tls握手确定将使用哪个协议。 -定义一个RemoteCertificateValIDationCallback()委托来验证X509Certificates服务器传递的X509Chain

实际上,建立TcpClIEnt或WebRequest连接时,Tls握手是相同的。 这种方法使您知道httpWebRequest 与同一服务器协商哪些Tls协议。

设置一个TcpClIEnt()以接收和评估SslStream。 该checkCertificateRevocation标志设置为false,因此该过程不会浪费时间来查找吊销列表。 证书验证回调与在中指定的相同ServicePointManager

TlsInfo tlsInfo = null;
IPHostEntry dnsHost = await Dns.GetHostEntryAsync(HostURI.Host);
using (TcpClIEnt clIEnt = new TcpClIEnt(dnsHost.Hostname, 443))
{
    using (SslStream sslStream = new SslStream(clIEnt.GetStream(), false, 
                                               TlsValIDationCallback, null))
    {
        sslstream.AuthenticateAsClIEnt(dnsHost.Hostname, null, 
                                      (SslProtocols)ServicePointManager.SecurityProtocol, false);
        tlsInfo = new TlsInfo(sslStream);
    }
}

//The httpWebRequest goes on from here.
httpWebRequest httpRequest = WebRequest.Createhttp(HostURI);

//(...)

TlsInfo级收集建立安全连接的一些信息: - -密码和Hash算法 - SSL握手中使用的服务器证书

public class TlsInfo
{
    public TlsInfo(SslStream SecureStream)
    {
        this.ProtocolVersion = SecureStream.SslProtocol;
        this.CipherAlgorithm = SecureStream.CipherAlgorithm;
        this.HashAlgorithm = SecureStream.HashAlgorithm;
        this.RemoteCertificate = SecureStream.RemoteCertificate;
    }

    public SslProtocols ProtocolVersion { get; set; }
    public CipherAlgorithmType CipherAlgorithm { get; set; }
    public HashAlgorithmType HashAlgorithm { get; set; }
    public X509Certificate RemoteCertificate { get; set; }
}

解决方法

我的应用程序在.NET 4.7中运行。默认情况下,它将尝试使用TLS1.2。例如,执行以下HTTP请求时,是否可以知道协商了哪个TLS版本?

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(decodedUri);
if (requestPayload.Length > 0)
{
    using (Stream requestStream = request.GetRequestStream())
    {
        requestStream.Write(requestPayload,requestPayload.Length);
    }
}

我仅出于日志记录/调试目的需要此信息,因此在写入请求流或接收响应之前获取此信息并不重要。我不希望为这些信息解析网络跟踪日志,也不想创建第二个连接(使用SslStream或类似的连接)。

大佬总结

以上是大佬教程为你收集整理的协商了哪个TLS版本?全部内容,希望文章能够帮你解决协商了哪个TLS版本?所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: