我正在尝试使用 CryptUnprotectData 将使用CryptProtectData保护的密码读入SecureString,然后使用该密码连接到数据库。我可以得到正确的密码,但是在此之后尝试创建新的SqlConnection失败,并显示以下内容:

System.TypeInitializationException was unhandled
  HResult=-2146233036
  Message=The type initializer for 'System.Data.SqlClient.SqlConnection' threw an exception.
  Source=System.Data
  TypeName=System.Data.SqlClient.SqlConnection
  StackTrace:
       at System.Data.SqlClient.SqlConnection..ctor()
       at System.Data.SqlClient.SqlConnection..ctor(String connectionString, SqlCredential credential)
       at System.Data.SqlClient.SqlConnection..ctor(String connectionString)
       at ProtectedSqlTest.Program.Main() in C:\Git\ProtectedSqlTest\ProtectedSqlTest\Program.cs:line 16
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException:
       HResult=-2146233036
       Message=The type initializer for 'System.Data.SqlClient.SqlConnectionFactory' threw an exception.
       Source=System.Data
       TypeName=System.Data.SqlClient.SqlConnectionFactory
       StackTrace:
            at System.Data.SqlClient.SqlConnection..cctor()
       InnerException:
            HResult=-2146233036
            Message=The type initializer for 'System.Data.SqlClient.SqlPerformanceCounters' threw an exception.
            Source=System.Data
            TypeName=System.Data.SqlClient.SqlPerformanceCounters
            StackTrace:
                 at System.Data.SqlClient.SqlConnectionFactory..cctor()
            InnerException:
                 HResult=-2147024809
                 Message=The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG))
                 Source=mscorlib
                 StackTrace:
                      at System.Globalization.TextInfo.InternalChangeCaseString(IntPtr handle, IntPtr handleOrigin, String localeName, String str, Boolean isToUpper)
                      at System.Globalization.TextInfo.ToLower(String str)
                      at System.String.ToLower(CultureInfo culture)
                      at System.Diagnostics.PerformanceCounterLib.GetPerformanceCounterLib(String machineName, CultureInfo culture)
                      at System.Diagnostics.PerformanceCounterLib.IsCustomCategory(String machine, String category)
                      at System.Diagnostics.PerformanceCounter.InitializeImpl()
                      at System.Diagnostics.PerformanceCounter.set_RawValue(Int64 value)
                      at System.Data.ProviderBase.DbConnectionPoolCounters.Counter..ctor(String categoryName, String instanceName, String counterName, PerformanceCounterType counterType)
                      at System.Data.ProviderBase.DbConnectionPoolCounters..ctor(String categoryName, String categoryHelp)
                      at System.Data.SqlClient.SqlPerformanceCounters..ctor()
                      at System.Data.SqlClient.SqlPerformanceCounters..cctor()
                 InnerException:

只需调用CryptUnprotectData就足以使SqlConnection失败,连接本身不需要使用返回的SecureString

我使用from here中描述的扩展方法this post来实现最小再现:
class Program
{
    const string ProtectedSecret = /* SNIP - base 64 encoded protected data here */;
    static void Main()
    {
        // calling AppendProtectedData breaks the following SqlConnection
        // without the following line the application works fine
        new SecureString().AppendProtectedData(Convert.FromBase64String(ProtectedSecret));

        using (var conn = new SqlConnection("Server=(localdb)\\MSSqlLocalDb;Trusted_Connection=true"))
        using (var cmd = new SqlCommand("select 1", conn))
        {
            conn.Open();
            cmd.ExecuteNonQuery();
        }
    }
}

如果我在加载密码之前创建了一个新的SqlConnection,那么我可以在应用程序运行期间创建新的SqlConnection,因为它似乎使用了相同的SqlConnectionFactory,但这意味着要解决此问题,我必须在开始时就这样做的应用程序:
new SqlConnection().Dispose();

...我想避免。

以下内容无济于事:
  • 调试与发布版本
  • 在Visual Studio中进行
  • 调试与通过命令行
  • 运行
  • 更改传递给CryptProtectFlagsCryptUnprotectData
  • 从保护方法中删除RuntimeHelpers.PrepareConstrainedRegions()

  • Windows 10,VS Enterprise 2015,控制台应用程序(.NET 4.6.1)

    更新:在另一个线程中运行数据保护代码会给出类似的异常,但具有不同的根本原因:
    System.TypeInitializationException was unhandled
      HResult=-2146233036
      Message=The type initializer for 'System.Data.SqlClient.SqlConnection' threw an exception.
      Source=System.Data
      TypeName=System.Data.SqlClient.SqlConnection
      StackTrace:
           at System.Data.SqlClient.SqlConnection..ctor()
           at System.Data.SqlClient.SqlConnection..ctor(String connectionString, SqlCredential credential)
           at System.Data.SqlClient.SqlConnection..ctor(String connectionString)
           at ProtectedSqlTest.Program.Main() in C:\Git\ProtectedSqlTest\ProtectedSqlTest\Program.cs:line 17
           at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
           at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
           at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
           at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
           at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
           at System.Threading.ThreadHelper.ThreadStart()
      InnerException:
           HResult=-2146233036
           Message=The type initializer for 'System.Data.SqlClient.SqlConnectionFactory' threw an exception.
           Source=System.Data
           TypeName=System.Data.SqlClient.SqlConnectionFactory
           StackTrace:
                at System.Data.SqlClient.SqlConnection..cctor()
           InnerException:
                HResult=-2146233036
                Message=The type initializer for 'System.Data.SqlClient.SqlPerformanceCounters' threw an exception.
                Source=System.Data
                TypeName=System.Data.SqlClient.SqlPerformanceCounters
                StackTrace:
                     at System.Data.SqlClient.SqlConnectionFactory..cctor()
                InnerException:
                     BareMessage=Configuration system failed to initialize
                     HResult=-2146232062
                     Line=0
                     Message=Configuration system failed to initialize
                     Source=System.Configuration
                     StackTrace:
                          at System.Configuration.ClientConfigurationSystem.EnsureInit(String configKey)
                          at System.Configuration.ClientConfigurationSystem.PrepareClientConfigSystem(String sectionName)
                          at System.Configuration.ClientConfigurationSystem.System.Configuration.Internal.IInternalConfigSystem.GetSection(String sectionName)
                          at System.Configuration.ConfigurationManager.GetSection(String sectionName)
                          at System.Configuration.PrivilegedConfigurationManager.GetSection(String sectionName)
                          at System.Diagnostics.DiagnosticsConfiguration.Initialize()
                          at System.Diagnostics.DiagnosticsConfiguration.get_SwitchSettings()
                          at System.Diagnostics.Switch.InitializeConfigSettings()
                          at System.Diagnostics.Switch.InitializeWithStatus()
                          at System.Diagnostics.Switch.get_SwitchSetting()
                          at System.Data.ProviderBase.DbConnectionPoolCounters..ctor(String categoryName, String categoryHelp)
                          at System.Data.SqlClient.SqlPerformanceCounters..ctor()
                          at System.Data.SqlClient.SqlPerformanceCounters..cctor()
                     InnerException:
                          HResult=-2147024809
                          Message=Item has already been added. Key in dictionary: 'MACHINE'  Key being added: 'MACHINE'
                          Source=mscorlib
                          StackTrace:
                               at System.Collections.Hashtable.Insert(Object key, Object nvalue, Boolean add)
                               at System.Collections.Hashtable.Add(Object key, Object value)
                               at System.Configuration.Internal.InternalConfigRoot.GetConfigRecord(String configPath)
                               at System.Configuration.ClientConfigurationSystem.EnsureInit(String configKey)
                          InnerException:
    

    最佳答案

    最近,我使用http://www.griffinscs.com/?p=12中的相同代码遇到了类似的症状:对CryptUnprotectData的任何调用都会导致某些无关代码中的异常。有趣的是,该故障仅发生在Windows 10计算机上。在Windows 7计算机上,相同的代码也可以正常工作。

    我通过将szDataDescrCryptProtectData中的CryptUnprotectData参数的声明从string更改为IntPtr,并在两个调用中传递IntPtr.Zero而不是string.Empty来解决了该问题。

    关于c# - P/调用CryptUnprotectData中断SqlConnection构造函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41241746/

    10-15 23:44