.net - .NET Web 服务客户端是否支持在备用主题名称中使用 IP 的 SSL 证书

标签 .net ssl names subject

我有一个应用程序,其中我们的许多端点不支持 DNS 查找,所以对于那些 他们无法使用 URL 访问我们的服务器的端点。 我们的应用程序给出了他们需要访问的我们服务器的 IP 列表,这对 http 工作正常。 我正在尝试启用 https 来访问我们的服务器,并且我已经创建了一个带有一些的 SAN 证书 url 作为主题备用名称加上我们服务器的 IP 作为主题备用名称。
例如在我用来创建 CSR 的 openssl.cnf 中:
DNS.1 = test.example.com
DNS.2 = test2.example.com
IP.1 = xxx.xxx.xxx.xxx
IP.2 = yyy.yyy.yyy.yyy

请注意,xxx 和 yyy 实际上是证书中的真实 IP 地址。

我们的 Java Web 服务客户端可以使用带有 IP 地址的 https 访问我们的服务器,没有问题。
我们的 .NET Web 服务客户端不能。
我正在为客户端使用 .NET Framework 3.5。
我正在使用 Tomcat 8 作为服务器。

.NET 客户端可以使用像 www.test.example.com 这样的comman name 和备用 test2.example.com 之类的名称,但如果我尝试使用 IP 地址,它会失败。
我从 system.diagnostics 启用了 Trace 以查看 SSL 握手提示的内容以及 我在来自服务器的一些数据中看到 DNS.x 的主题备用名称正在 发送到客户端但 IP 没有,因此无法在证书中找到 IP 作为替代。

[主题]
CN=www.test.example.com, O=Epicor Software Corporation, L=Austin, S=Texas,
C=US
简单名称:www.test.example.com
DNS 名称:test.example.com

[发行人]
CN=DigiCert SHA2 安全服务器 CA,O=DigiCert Inc,C=US
简单名称:DigiCert SHA2 安全服务器 CA
DNS 名称:DigiCert SHA2 安全服务器 CA

[序列号]
0DB4E110FDCE072E4D98F756B3D66B3C

[之前没有]
2016 年 3 月 27 日下午 7:00:00

[不在]
2017 年 4 月 19 日上午 7:00:00

[指纹]
6FBC98CA67D77121BC934E0A1AC5AB552EAB88ED

[签名算法]
sha256RSA(1.2.840.113549.1.1.11)

[公钥]
算法:RSA
长度:2048
key block :30 82 01 0a 02 82 01 01 00 ca 24 0b f0 f4 f6 58 1d 53 f6 5e 11 e6 7c 07 ae 81 4e bd b8 8d 6c ff 2c 7b c9 21 6f d4 99 86 9c 04 23 2 5 8b 34 31 dd 1c 85 1a 0c 86 34 a3 32 a1 17 12 3f c1 45 bf 38 3d 37 19 29 9c 44 e8 d0 b3 d6 92 9d 3d 9c ad 31 24 55 41 86 1a 2e ff 4c cb bf 32 0a 48 24 05 3f 加州0a 3c 8d f6 e0 31 14 3a a3 d8 7b 97 7b 3d 98 80 3a d8 f6 76 ca....
ProcessId=20004
日期时间=2017-02-27T21:22:06.0846039Z
System.Net 信息:0:[22244] SecureChannel#66166301 - 远程证书有错误:
ProcessId=20004
日期时间=2017-02-27T21:22:06.1146042Z
System.Net 信息:0:[22244] SecureChannel#66166301 - 证书名称不匹配。
ProcessId=20004
日期时间=2017-02-27T21:22:06.1146042Z
System.Net 信息:0:[22244] SecureChannel#66166301 - 远程证书被用户验证为无效。
ProcessId=20004
日期时间=2017-02-27T21:22:06.1146042Z
System.Net.Sockets 详细:0:[22244] Socket#15688314::Dispose()
ProcessId=20004
日期时间=2017-02-27T21:22:06.1146042Z
System.Net 错误:0:[22244] HttpWebRequest 中的异常#35320229::- 基础连接已关闭:无法为 SSL/TLS 安全通道建立信任关系。

最佳答案

在 Steffens 的帮助下,我找到了 Schannel 和 IP 地址字段以及许多其他研究,我找到了这个问题的答案。

.NET 不支持直接将 IP 地址作为主题备用名称,因为它依赖于 Schannel 来验证证书中的 IP 地址。

Schannel 仅在证书的“DNS 名称=”字段中查找 https 请求中给出的主机名 (IP)。因此,如果您可以让 CA 为您提供“DNS 名称 =”字段中列出的 IP 地址的证书,那么它可能会起作用。 但是,我的 CA 不允许将 IP 地址放在“DNS 名称=”字段中,并要求它们放在“IP 地址=”字段中,因为这是现在的行业标准。

所以这意味着当 Schannel 在证书中找不到 IP 时,它将收到证书不匹配错误。

然后它会在 ServicePointManager.ServerCertificateValidationCallback 属性中查找要调用的方法,以要求用户验证证书,默认情况下此属性设置为 None。 所以它直接拒绝连接。

此处以 c# 为例,您可以创建自己的回调方法并将其分配给 ServicePointManager.ServerCertificateValidationCallback 属性。 该方法采用作为请求中使用的 WebRequest 对象的发件人对象、作为证书的 X509Certificate、X509Chain 和 SslPolicyErrors 值,如果在 URL 中使用 IP,则该值将是错误 SslPolicyErrors.RemoteCertificationNameMismatch。

        private void init()
    {
        // Add a custom callback for server validation so that https to IP addresses will work.
        // See comments in InternalCallback method for more details
        ServicePointManager.ServerCertificateValidationCallback += this.InternalCallback;
    }
        private bool InternalCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        // The security package on Windows OS known as Schannel provides the authentication between
        // clients and servers.
        // If you are using https with an IP to a server with a cert that has IP addresses in the Subject Alternative Names,
        // Schannel fails to find those IPs among the "IP Address=" fields in the cert.
        // Schannel only looks at the DNS Name= fields.
        // consequently Schannel will pass SslPolicyErrors.RemoteCertificationNameMismatch error to the 
        // ServicePointManager.ServerCertificateValidationCallback method which will cause the SSL connectino
        // to be rejected.
        // By default the ServicePointManager.ServerCertificateValidationCallback = None which I guess means
        // Schannel rejects the connection outright because of the mismatch error.
        // You can create a callback method like this one and assign it to the ServerCertificateValidationCallback
        // property so that you can do the validation yourself.
        //
        // The sender passed to this method is the WebRequest which contains the url used to hit the service.
        // The certificate is also passed to this method and you can use ToString(true) to get a verbose listing
        // of the cert that contains the Subject Alternative Names including the "IP Address=" fields.
        // This method will get the hostname of of the URL and if it is an IP address it will check to make
        // sure the cert contains the IP used and if so will return true (ignoring the sslPolicyErrors value.
        // If the hostname is not an IP then it will check that the hostname is found in the cert and that
        // the sslPolicyErrors contains the value of None before returning true.
        // This way we still do full validation of a hostname url and ignore validation errors when using an IP.
        Regex      ipv4Validator      = new Regex("((25[0-5]|(2[0-4]|1\\d|[1-9])?\\d)(\\.|$)){4}");
        WebRequest request    = (WebRequest)sender;
        UriBuilder theuri     = new UriBuilder(request.RequestUri);
        String     thecert    = certificate.ToString(true);
        bool       containsIP = ipv4Validator.IsMatch(theuri.Host);

        if (sslPolicyErrors == SslPolicyErrors.None)
            logger.Info("Settings.InternalCallback() sslPolicyErrors = " + sslPolicyErrors.ToString());
        else
        {
            logger.Info("Settings.InternalCallback() " + (containsIP ? "IP was used so ignoring " : "" ) + " sslPolicyErrors = " + sslPolicyErrors.ToString());
        }
        logger.Debug("Settings.InternalCallback() requesturi = " + request.RequestUri);
        logger.Debug("Settings.InternalCallback() subject = " + certificate.Subject);
        logger.Debug("Settings.InternalCallback() request host = " + theuri.Host);
        logger.Debug("Settings.InternalCallback() certificate verbose = " + thecert);
        // possible sslPolicyErrors are:
        // None
        // RemoteCertificateChainErrors
        // RemoteCertificateNameMismatch
        // RemoteCertificateNotAvailable
        // If the request was sent to an IP then we will get a RemoteCertificateNameMismatch
        //   error so ignore it and just check that the IP is found in the cert.
        if (containsIP)
           return thecert.Contains(theuri.Host);
        else
           return thecert.Contains(theuri.Host) && sslPolicyErrors == SslPolicyErrors.None;
    }

关于.net - .NET Web 服务客户端是否支持在备用主题名称中使用 IP 的 SSL 证书,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42517028/

相关文章:

c# - 命令提示符下的 MsBuild 未生成 FakeAssemblies

.net - 如何在没有返回变量的情况下调试 VB.NET 计算函数返回

jquery - JQGrid - 创建没有列名的网格

r - 在R中命名列表元素

c# - 仅处理消息队列中的部分消息

.htaccess - 我需要在主域而不是子域上强制使用 ssl

ssl - webview_flutter "Failed to validate the certificate chain"SSL握手失败错误

apache - 在 apache 上安装 p7b

iphone - 如何在 iOS - iPhone 上为同一类的不同实例命名

c# - 在 C# 中附加列表时处理列表?