无法使用证书通过Windows 10 1809中的com-interop登录网站

问题描述 投票:5回答:1

下面的C#代码,登录到网站,

  • 通过com-interop从Excel 2010 VBA在计算机A上调用时工作
  • 从C#控制台应用程序调用计算机B时工作,但是
  • 通过com-interop从Excel 2010 VBA在计算机B上调用时失败

计算机A和计算机B之间的主要区别在于计算机A具有Windows 10版本1803,而计算机B具有Windows 10版本1809.两台计算机都具有Studio 2017,并且在所有情况下目标.Net Framework是4.6.2。

using System;
using System.Runtime.InteropServices;
using System.IO;

[Guid("97E1D9DB-8478-4E56-9D6D-26D8EF13B100")]
[ComVisible(true)]
public interface IToExcel {
    string Do();
}

[Guid("BBF87E31-77E2-46B6-8093-1689A144BFC6")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public class Main : IToExcel {
    private const string XAPP_ID = "...";
    private const string USERNAME = "...";
    private const string PASSWORD = "...";
    private const string CERT_FILE = @"...";
    private const string CERT_PASSWORD = "...";
    private const string WEBSITE = "https:// ...";

    public string Do() {
        System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(new Uri(WEBSITE));
        request.AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate;
        request.Method = "POST";
        request.Accept = "application/json";
        request.Timeout = request.ReadWriteTimeout = 20000;
        request.ContentType = "application/x-www-form-urlencoded";
        request.UseDefaultCredentials = true;
        request.Proxy = null;
        // setup headers
        System.Net.WebHeaderCollection whc = new System.Net.WebHeaderCollection {
            { "X-Application", XAPP_ID },
            { System.Net.HttpRequestHeader.AcceptCharset, "utf-8" },
            { System.Net.HttpRequestHeader.AcceptEncoding, "gzip,deflate" }
        };
        request.Headers.Add(whc);
        // setup certificate
        System.Security.Cryptography.X509Certificates.X509Certificate2 m_x509certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(CERT_FILE, CERT_PASSWORD);
        request.ClientCertificates.Add(m_x509certificate);
        // do call
        using (Stream stream = request.GetRequestStream()) {
            using (StreamWriter writer = new StreamWriter(stream, System.Text.Encoding.Default)) {
                writer.Write("username=" + USERNAME + "&password=" + PASSWORD);
            }
        }
        string responseData = string.Empty;
        using (System.Net.WebResponse response = request.GetResponse()) {
            using (Stream responseStream = response.GetResponseStream()) {
                using (StreamReader reader = new StreamReader(responseStream, System.Text.Encoding.UTF8)) {
                    responseData = reader.ReadToEnd();
                }
            }
        }
        return responseData;
    }

}

在所有情况下都返回一个小JSON对象,其中JSON对象有一个名为“loginStatus”的字段。当它工作时,“loginStatus”=“SUCCESS”,但是当它失败时“loginStatus”=“CERT_AUTH_REQUIRED”。

我试着查看System.Net.ServicePointManager中的所有设置,但在所有情况下设置都是相同的:

  • ReusePort:错误
  • ServerCertificateValidationCallback:
  • DnsRefreshTimeout:120000
  • EnableDnsRoundRobin:False
  • Expect100Continue:是的
  • UseNagleAlgorithm:True
  • Masservisapointeidletime:100000
  • DefaultConnectionLimit:2
  • MasserVichePoints:0
  • SecurityProtocol:Tls,Tls11,Tls12
  • CheckCertificateRevocationList:False
  • EncryptionPolicy:RequireEncryption

除此之外,我不知道还有什么要检查。从.Net 4.6.2升级到4.7.1无效,结果相同。

我想知道这是否是Windows 1809中的一个错误,但是因为它直接在.Net控制台应用程序中调用它,我认为这是一个微妙的配置问题。任何人都可以帮我从计算机B上的Excel 2010中获得这个功能吗?

更新于201年2月8日

正如评论中所建议的那样,我使用Fiddler来检查正在对网站进行的https调用的结构。两个工作看起来相同,失败的看起来略有不同:

呼叫正常工作

  • TLS扩展名ec_point_formats =未压缩[0x0]
  • 未指定TLS扩展encrypt_then_mac(RFC7366)
  • TLS扩展名renegotiation_info = 0
  • 未指定密码TLS_EMPTY_RENEGOTIATION_INFO_SCSV

电话失败

  • TLS扩展名ec_point_formats =未压缩[0x0],ansiX962_compressed_prime [0x1],ansiX962_compressed_char2 [0x2]
  • TLS扩展名encrypt_then_mac(RFC7366)=空
  • 未指定TLS扩展renegotgot_info
  • 指定了密码TLS_EMPTY_RENEGOTIATION_INFO_SCSV

但现在我有了这些信息,我不确定它是否有帮助。也许有效的调用都是由相同的低级代码生成的(尽管它们位于不同版本的Windows 10上),并且失败的调用是由不同的低级代码生成的。

更新于201年2月10日

通过com-interop从Excel调用时,我使代码在新的AppDomain中执行EXE,而不是直接调用登录代码。当我这样做时,EXE无法工作并产生相同的输出,就像我直接调用登录代码一样。

下面是一些Visual Studio Output窗口,它显示了EXE文件运行时加载DLL的顺序,就在登录代码执行之前。成功的场景和失败的场景之间的最大区别在于失败的场景永远不会加载C:\ Windows \ System32 \ ncryptprov.dll。有谁知道导致该DLL加载的原因是什么?

(Win32):加载'C:\ Windows \ System32 \ msisip.dll'

(Win32):加载'C:\ Windows \ System32 \ coml2.dll'---从EXCEL加载更早

(Win32):加载'C:\ Windows \ System32 \ wshext.dll'

(Win32):加载'C:\ Windows \ System32 \ AppxSip.dll'

(Win32):加载'C:\ Windows \ System32 \ tdh.dll'

(Win32):加载'C:\ Windows \ System32 \ xmllite.dll'

(Win32):加载'C:\ Windows \ System32 \ OpcServices.dll'

(Win32):加载'C:\ Windows \ System32 \ mintdh.dll'

(Win32):加载'C:\ Windows \ System32 \ urlmon.dll'---从EXCEL加载更早

(Win32):加载'C:\ Windows \ System32 \ mintdh.dll'

(Win32):卸载'C:\ Windows \ System32 \ mintdh.dll'

(Win32):加载'C:\ Windows \ System32 \ iertutil.dll'---从EXCEL加载更早

(Win32):加载'C:\ Windows \ System32 \ WindowsPowerShell \ v1.0 \ pwrshsip.dll'

(Win32):加载'C:\ Windows \ System32 \ EsdSip.dll'

(Win32):加载'C:\ Windows \ System32 \ userenv.dll'---从EXCEL加载更早

(Win32):加载'C:\ Windows \ System32 \ dpapi.dll'

(Win32):加载'C:\ Windows \ System32 \ dnsapi.dll'

(Win32):加载'C:\ Windows \ System32 \ rasadhlp.dll'

(Win32):加载'C:\ Windows \ System32 \ FWPUCLNT.DLL'

(Win32):加载'C:\ Windows \ System32 \ secur32.dll'

(Win32):加载'C:\ Windows \ System32 \ sspicli.dll'---从EXCEL加载更早

(Win32):加载'C:\ Windows \ System32 \ schannel.dll'

(Win32):加载'C:\ Windows \ System32 \ mskeyprotect.dll'

(Win32):加载'C:\ Windows \ System32 \ ncrypt.dll'

(Win32):加载'C:\ Windows \ System32 \ ntasn1.dll'

(Win32):加载'C:\ Windows \ System32 \ ncryptprov.dll'---没有从EXCEL加载

(Win32):加载'C:\ Windows \ System32 \ ncryptsslp.dll'

此时C#代码执行

更新于201年2月12日

很多感谢Simon Mourier告诉我如何设置System.Net诊断。在计算机B上运行诊断程序,获得两个案例输出的“System.Net信息”行开始时相同,但最终会有所不同。这是计算机B上Console EXE文件的输出(即有效的情况):

System.Net Information: 0 : [35268] Current OS installation type is 'Client'.
System.Net Information: 0 : [35268] RAS supported: True
System.Net Information: 0 : [35268] Associating HttpWebRequest#21454193 with ServicePoint#34640832
System.Net Information: 0 : [35268] Associating Connection#43332040 with HttpWebRequest#21454193
System.Net Information: 0 : [35268] Connection#43332040 - Created connection from XXX.XXX.XXX.XXX:53002 to YYY.YYY.YYY.YYY:443.
System.Net Information: 0 : [35268] TlsStream#54444047::.ctor(host=<TargetWebSite>, #certs=1, checkCertificateRevocationList=False, sslProtocols=Tls12)
System.Net Information: 0 : [35268] Associating HttpWebRequest#21454193 with ConnectStream#20234383
System.Net Information: 0 : [35268] HttpWebRequest#21454193 - Request: POST /api/certlogin HTTP/1.1
System.Net Information: 0 : [35268] ConnectStream#20234383 - Sending headers
System.Net Information: 0 : [35268] SecureChannel#47891719::.ctor(hostname=<TargetWebSite>, #clientCertificates=1, encryptionPolicy=RequireEncryption)
System.Net Information: 0 : [35268] Enumerating security packages:
System.Net Information: 0 : [35268]     Negotiate
System.Net Information: 0 : [35268]     NegoExtender
System.Net Information: 0 : [35268]     Kerberos
System.Net Information: 0 : [35268]     NTLM
System.Net Information: 0 : [35268]     TSSSP
System.Net Information: 0 : [35268]     pku2u
System.Net Information: 0 : [35268]     CloudAP
System.Net Information: 0 : [35268]     WDigest
System.Net Information: 0 : [35268]     Schannel
System.Net Information: 0 : [35268]     Microsoft Unified Security Protocol Provider
System.Net Information: 0 : [35268]     Default TLS SSP
System.Net Information: 0 : [35268]     CREDSSP
System.Net Information: 0 : [35268] SecureChannel#47891719 - Attempting to restart the session using the user-provided certificate: [Version]
System.Net Information: 0 : [35268] SecureChannel#47891719 - Left with 1 client certificates to choose from.
System.Net Information: 0 : [35268] SecureChannel#47891719 - Trying to find a matching certificate in the certificate store.
System.Net Information: 0 : [35268] SecureChannel#47891719 - Locating the private key for the certificate: [Version]
System.Net Information: 0 : [35268] SecureChannel#47891719 - Certificate is of type X509Certificate2 and contains the private key.
System.Net Information: 0 : [35268] SecureChannel#47891719::.AcquireClientCredentials, new SecureCredential() (flags=(ValidateManual, NoDefaultCred, SendAuxRecord, UseStrongCrypto), m_ProtocolFlags=(Tls12Client), m_EncryptionPolicy=RequireEncryption)
System.Net Information: 0 : [35268] AcquireCredentialsHandle(package = Microsoft Unified Security Protocol Provider, intent  = Outbound, scc     = System.Net.SecureCredential)
System.Net Information: 0 : [35268] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = (null), targetName = <TargetWebSite>, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [35268] InitializeSecurityContext(In-Buffer length=0, Out-Buffer length=184, returned code=ContinueNeeded).
System.Net Information: 0 : [35268] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 227c85a89b0:2449d0deff0, targetName = <TargetWebSite>, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [35268] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=CredentialsNeeded).

但是,当从Excel 2010通过com-interop运行时,而不是最后4个InitializeSecurityContext行,有6个InitializeSecurityContext行,如下所示:

System.Net Information: 0 : [39988] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = (null), targetName = <TargetWebSite>, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [39988] InitializeSecurityContext(In-Buffer length=0, Out-Buffer length=184, returned code=ContinueNeeded).
System.Net Information: 0 : [39988] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 8a8e2f0:2449d0def90, targetName = <TargetWebSite>, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [39988] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
System.Net Information: 0 : [39988] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 8a8e2f0:2449d0def90, targetName = <TargetWebSite>, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [39988] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).

前两个InitializeSecurityContext行是相同的,因此可能关键的区别在于第三个InitializeSecurityContext行,其中控制台EXE具有

context = 227c85a89b0:2449d0deff0

但是通过com-interop executino失败了

context = 8a8e2f0:2449d0def90

在那之后,事情看起来并不像人们所期望的那样。有谁知道这个差异意味着什么,以及如何使差异消失,以便com-interop执行的行为与com-interop执行相同?

更新于201年2月13日

我在an MSDN forum上发布了更多的诊断输出。

.net excel vba https com-interop
1个回答
2
投票

专注于C#控制台与Excel 2010问题(同一台计算机,均作为64位进程运行),添加了跟踪,如下所述:https://stackoverflow.com/a/25683524/403671

Excel和控制台的初始跟踪完全相同(有关详细信息,请参阅问题)。但最后的痕迹(发布到MSDN)表明:

安慰:

System.Net Information: 0 : [35268] Remote certificate: [Version] V3
[ Lots of lines describing a certificate with [Subject]=<TargetWebSite>, [Issuer]=HydrantID SSL ICA G2, etc]
System.Net Information: 0 : [35268] SecureChannel#47891719 - Remote certificate was verified as valid by the user.    

Excel中:

System.Net Information: 0 : [39988] Remote certificate: [Version] V3
[ Lots of lines describing a certificate with [Subject]=<TargetWebSite>, [Issuer]=Kaspersky, etc]
System.Net Information: 0 : [39988] SecureChannel#2383799 - Remote certificate was verified as valid by the user.

它显示了Excel中使用的证书现在由卡巴斯基发布,结果证明是在PC上运行的防病毒产品。事实上,它是intercept communications的卡巴斯基产品安全功能,这会导致许多问题,例如KIS Interfering with Git

删除此防病毒后,一切都按预期工作。

© www.soinside.com 2019 - 2024. All rights reserved.