2009-10-13 8 views
5

Ich hatte schon immer das Gefühl, dass SecureString etwas seltsam war, aber ich vermutete, dass die meisten meiner Probleme damit zusammenhingen, dass ich Sicherheitsprobleme nicht verstand. Heute habe ich beschlossen, mich hinzusetzen und mir selbst etwas beizubringen, aber ich habe etwas erreicht, was wie ein tödlicher Haken aussieht.Ist es möglich, sicher einen SecureString-Wert von VB .NET zu erhalten?

Das Szenario, das ich mir vorstelle, ist "der Benutzer gibt ein Passwort in das Textfeld ein, das Passwort wird gehashed und mit einem gespeicherten Hash verglichen". Zuerst hatte ich Bedenken, dass das Textfeld die Zeichenfolge enthielt, aber dann wurde mir klar, dass Sie ein benutzerdefiniertes Textfeld rollen können, das SecureString als Speicher verwendet. Cool. Es ist das "dieses Passwort ist gehashed und verglichen ..." Teil, der mir Probleme bereitet.

Mein erster Hack auf dem Problem in VB .NET war naiv und falsch:

Dim passwordHandle As IntPtr 
Dim insecurePassword As String = Nothing 
Try 
    passwordHandle = Marshal.SecureStringToBSTR(_password) 
    insecurePassword = Marshal.PtrToStringBSTR(passwordHandle) 
Catch ex As Exception 

Finally 
    If passwordHandle <> IntPtr.Zero Then 
     Marshal.ZeroFreeBSTR(passwordHandle) 
    End If 
End Try 

If insecurePassword <> Nothing Then 
    ' Do hash and comparison 
End If 

Diese stopft nur das Passwort in eine reguläre String und besiegt den Zweck Secure in erster Linie zu verwenden. Also habe ich weiter gesucht und a blog post gefunden, das das Problem in C# gut löst: Die Zeichenfolge wird zu einem BSTR gemacht, in eine gepinnte Zeichenfolge kopiert, dann werden sowohl die BSTR als auch die angeheftete Zeichenfolge nach der Verwendung auf Null gesetzt. Dies scheint eine viel bessere Idee zu sein, da es den Zeitraum minimiert, in dem sich die unsichere Zeichenfolge im Speicher befindet. Es sieht jedoch nicht so aus, als gäbe es eine Möglichkeit, dies in VB .NET zu lösen. C# verwendet seine unsichere Code-Funktion, um Zeigermanipulationen durchzuführen, aber VB .NET kann dies nicht tun. Ich habe mir Marshsall.Copy() angeschaut, aber es sieht so aus, als wäre es auf Arrays ausgerichtet. Ich dachte darüber nach zu versuchen, die IntPtr-Variablen für das Objekt und BSTR in Strings zu werfen, aber das ließ mich immer noch eine Methode wie String.Replace(), die eine neue Zeichenfolge erstellen wird.

Ist es nicht möglich, dies von VB .NET überhaupt zu tun, oder fehlt mir etwas?

bearbeiten Ich akzeptiere die Antwort von AMissico mit nur geringen Vorbehalten. Die Marshal.ReadByte() - Methode kopiert ein Byte aus dem nicht verwalteten Speicher und erstellt ein Byte im nicht verwalteten Speicher. Dies ergibt die geringe Chance, dass ein Angreifer die einzelnen Zeichen des Passworts findet. Ich denke, das ist weit weniger als die Wahrscheinlichkeit, eine ganze Zeichenfolge zu finden, aber das C# in dem Artikel, auf den ich verwiesen habe, war in der Lage, unsicheren Code zu verwenden, um dies sauber zu vermeiden. Der Denkprozess war es GCHandle verwendet, um eine Zeichenfolge im Speicher fest, dann verwendet unsicheren Code, um die Unveränderlichkeit der .NET-Zeichenfolgen zu umgehen. Cleverer Trick, der in VB .NET unmöglich erscheint. Ich werde versuchen, mit dem C# -Code selbst zurück zu kommen.

+0

Gibt es einen Grund, dass es in VB.NET geschrieben werden müssen? Wenn C# die erforderliche Unterstützung besser unterstützt, würde ich die Lösung in C# schreiben. –

+1

Der Grund ist, weil es etwas ist, das ich Leuten zeigen möchte, die mit VB .NET am wohlsten sind. Dennoch ist es keine Antwort, dies zu sagen. Angenommen, ich hätte eine 100.000-Zeilen umfassende Unternehmensanwendung in VB .NET geschrieben; Wäre es wirklich sinnvoll, eine Klassenbibliothek für 1 C# -Datei zu erstellen, um dies zu unterstützen? Dies ist eine Klasse, die Teil des .NET Framework ist und für einen relativ häufigen Anwendungsfall wichtig ist. Wenn eine der primären .NET-Sprachen es nicht verwenden kann, ist das eine ziemlich große Sache. – OwenP

+0

* Shrugs * - Aus dem Artikel, mit dem Sie verlinkt haben, scheint das Problem, dass SecureString relativ neu ist, und sobald der Rest des Frameworks aktualisiert ist, kann es verwendet werden, ohne es jemals in einen String umzuwandeln, und alles wird gut (in VB und C#). Persönlich, wenn etwas getan werden muss, mache ich es, auch wenn das bedeutet, eine kleine Klassenbibliothek in einer anderen Sprache zu verwenden. –

Antwort

3

Der Link zu "Marshalling SecureString Passwords zu String - Mark Nicholson " bei http://dotnet.org.za/markn/archive/2008/10/04/handling-passwords.aspx schließlich angezeigt.

Ihre Anweisung, "C# verwendet seine unsichere Code-Funktion, um Zeigermanipulationen zu tun", scheint mit "How to: Umbrechen eines UCOMIStream in einer Stream-Klasse in Visual Basic .NET" um http://support.microsoft.com/kb/321695. (Ich suchte auf "AddrOfPinnedObject".)

Ich habe nicht Ihre ganze Frage gelesen (Link zum Beitrag immer abgelaufen), aber sind diese Klassen und Testcode hilfreich? Das Passwort lebt niemals als System.String; Daher benötigen Sie eine SecureStringTextBox-Implementierung, wie in Ihrer Frage angegeben.

Ich mag es nicht, all diesen Code hinzuzufügen. Lass mich wissen, welcher Code hilfreich ist, und ich werde die Antwort bearbeiten, um nur das hilfreiche Zeug zu behalten.

Imports System.Security 
Imports System.Security.Principal 
Imports System.Security.Permissions 
Imports System.Runtime.InteropServices 

''' <summary> 
''' Helper class to programmatically impersonate a user, load and unload a user's profile, and perform other maintenance-related tasks for impersonating a user. 
''' </summary> 
Public Class ImpersonationHelper 
    Implements IDisposable 

#Region " IDisposable Implementaton " 

    Private _disposed As Boolean 

    Protected Overrides Sub Finalize() 
     Dispose(False) 
     MyBase.Finalize() 
    End Sub 

    ''' <summary> 
    ''' Implementation of the <b>IDisposable</b> interface. 
    ''' </summary> 
    ''' <remarks>This method calls <see>Undo</see> if impersonation is still being performed. This method calls the common language runtime version of the Dispose method.</remarks> 
    Public Overloads Sub Dispose() Implements IDisposable.Dispose 
     Dispose(True) 
     System.GC.SuppressFinalize(Me) 
    End Sub 

    ''' <summary> 
    ''' Implementation of the <b>IDisposable</b> interface. 
    ''' </summary> 
    ''' <param name="disposing">If <b>true</b>, the object to be disposed is finalized and collected by the garbage collector; otherwise, <b>false</b>.</param> 
    ''' <remarks>This method calls Undo if impersonation is still being performed. This method calls the common language runtime version of the Dispose method.</remarks> 
    Protected Overloads Sub Dispose(ByVal disposing As Boolean) 
     If Not _disposed Then 
      If disposing Then 
       If Not IsNothing(_impersonationContext) Then 
        _impersonationContext.Undo() 
        _impersonationContext.Dispose() 
       End If 
      End If 
      _impersonationContext = Nothing 
     End If 
     _disposed = True 
    End Sub 

#End Region 

    '2009.02.12 AMJ 
    ' Modified From: 
    '  How to implement impersonation in an ASP.NET application (KB306158) 
    '  http://support.microsoft.com/kb/306158 
    ' Implemented IDisposable based on ImpersonationHelper class of 
    '  Namespace: Microsoft.Office.Excel.Server.Addins.ComputeCluster.Security 
    '  Assembly: Microsoft.Office.Excel.Server.Addins.ComputeCluster (in microsoft.office.excel.server.addins.computecluster.dll) 

    Const LOGON32_LOGON_INTERACTIVE As Integer = 2 
    Const LOGON32_LOGON_BATCH As Integer = 4 
    Const LOGON32_LOGON_SERVICE As Integer = 5 

    Const LOGON32_PROVIDER_DEFAULT As Integer = 0 
    Const LOGON32_PROVIDER_WINNT35 As Integer = 1 

    Private Enum SECURITY_IMPERSONATION_LEVEL 
     SecurityAnonymous = 0 
     SecurityIdentification = 1 
     SecurityImpersonation = 2 
     SecurityDelegation = 3 
    End Enum 

    Private Declare Auto Function LogonUser Lib "advapi32.dll" (_ 
     ByVal username As String, _ 
     ByVal domain As String, _ 
     ByVal password As IntPtr, _ 
     ByVal logonType As Integer, _ 
     ByVal logonProvider As Integer, _ 
     ByRef token As IntPtr) As Boolean 

    Private Declare Auto Function DuplicateToken Lib "advapi32.dll" (_ 
     ByVal ExistingTokenHandle As IntPtr, _ 
     ByVal ImpersonationLevel As SECURITY_IMPERSONATION_LEVEL, _ 
     ByRef DuplicateTokenHandle As IntPtr) As Integer 

    Private Declare Auto Function RevertToSelf Lib "advapi32.dll"() As Long 
    Private Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Long 

    Dim _impersonationContext As WindowsImpersonationContext 
    Dim _domain As String 
    Dim _login As String 
    Dim _password As SecureString 

#Region " Standard Constructor & Properties " 

    ''' <summary> 
    ''' Initializes a new instance of the ImpersonationHelper class. 
    ''' </summary> 
    ''' <param name="domain">The domain or computer name of the user to impersonate.</param> 
    ''' <param name="userName">The user name of the user to impersonate.</param> 
    ''' <param name="password">The secure string password of UserName. For more information about secure strings, see the <see cref="System.Security.SecureString">SecureString</see> class.</param> 
    <DebuggerNonUserCode()> _ 
    Public Sub New(ByVal domain As String, ByVal userName As String, ByVal password As SecureString) 
     Me.Domain = domain 
     Me.Login = userName 
     Me.Password = password 
    End Sub 

    ''' <summary> 
    ''' Do not allow a new instance of the ImpersonationHelper class without credentials. 
    ''' </summary> 
    Private Sub New() 

    End Sub 

    ''' <summary> 
    ''' Gets or sets the domain of the user to impersonate. 
    ''' </summary> 
    ''' <value>The domain of the user.</value> 
    <DebuggerNonUserCode()> _ 
    Public Property Domain() As String 
     Get 
      Return _domain 
     End Get 
     Set(ByVal value As String) 
      _domain = value 
     End Set 
    End Property 

    ''' <summary> 
    ''' Gets or sets the user name of the user to impersonate. 
    ''' </summary> 
    ''' <value>The user name.</value> 
    <DebuggerNonUserCode()> _ 
    Public Property Login() As String 
     Get 
      Return _login 
     End Get 
     Set(ByVal value As String) 
      _login = value 
     End Set 
    End Property 

    ''' <summary> 
    ''' Sets the encrypted password of the user to impersonate. 
    ''' </summary> 
    ''' <value>The encrypted password.</value> 
    <DebuggerNonUserCode()> _ 
    Public WriteOnly Property Password() As SecureString 
     Set(ByVal value As SecureString) 
      _password = value 
     End Set 
    End Property 

#End Region 

    ''' <summary> 
    ''' Performs the impersonation of the user based on the parameters provided in the constructor. 
    ''' </summary> 
    ''' <remarks> 
    ''' <para>If logon fails using the supplied credentials, an exception is thrown. The exception is thrown because this method is unable to duplicate the logged-on user's token for purposes of impersonation or is unable to create a Windows identity from the user's impersonated token.</para> 
    ''' <para>For details about the direct cause of the impersonation failure, you can inspect the inner exception.</para> 
    ''' </remarks> 
    <PermissionSetAttribute(SecurityAction.Demand, Name:="FullTrust")> _ 
    Public Sub ImpersonateUser() 

     Dim fResult As Boolean = False 'assume impersonation failed 

     Dim hPassword As IntPtr = IntPtr.Zero 
     Dim hToken As IntPtr = IntPtr.Zero 
     Dim hTokenDuplicate As IntPtr = IntPtr.Zero 
     Dim oException As ImpersonationException = Nothing 

     If RevertToSelf <> 0 Then 

      hPassword = Marshal.SecureStringToGlobalAllocUnicode(_password) 

      If LogonUser(Me.Login, Me.Domain, hPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, hToken) Then 
       If DuplicateToken(hToken, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, hTokenDuplicate) <> 0 Then 
        _impersonationContext = New WindowsIdentity(hTokenDuplicate).Impersonate() 
        If Not _impersonationContext Is Nothing Then 
         fResult = True 
        End If 
       End If 
      Else 
       oException = New ImpersonationException(Me.Login, Me.Domain) 
      End If 

      If hPassword.Equals(IntPtr.Zero) = False Then 
       Marshal.ZeroFreeGlobalAllocUnicode(hPassword) 
      End If 

     End If 

     If Not hTokenDuplicate.Equals(IntPtr.Zero) Then 
      CloseHandle(hTokenDuplicate) 
     End If 

     If Not hToken.Equals(IntPtr.Zero) Then 
      CloseHandle(hToken) 
     End If 

     If Not (oException Is Nothing) Then 
      Throw oException 
     End If 

    End Sub 

    ''' <summary> 
    ''' Undoes the impersonation of the user, if it is impersonated. 
    ''' </summary> 
    ''' <remarks>Use this method to free the objects associated with impersonation.</remarks> 
    <PermissionSetAttribute(SecurityAction.Demand, Name:="FullTrust")> _ 
    <DebuggerNonUserCode()> _ 
    Public Sub Undo() 
     _impersonationContext.Undo() 
     _impersonationContext = Nothing 
    End Sub 

    Public Shared Function InvokeAsUser(ByVal userName As String, ByVal domain As String, ByVal password As SecureString, ByVal methodToCall As [Delegate], ByVal ParamArray parameters() As Object) As Object 
     Dim oResult As Object = Nothing 

     Using oImpersonation As New ImpersonationHelper(domain, userName, password) 

      oImpersonation.ImpersonateUser() 

      oResult = methodToCall.DynamicInvoke(parameters) 

     End Using 

     Return oResult 
    End Function 

End Class 

Public Class ImpersonationException 
    Inherits System.Exception 

    Public ReadOnly Login As String 
    Public ReadOnly Domain As String 

    Public Sub New(ByVal userName As String, ByVal domain As String) 
     MyBase.New(String.Format("Impersonation failure: {1}\{0}", userName, domain), New System.ComponentModel.Win32Exception) 
    End Sub 

End Class 

Imports Missico.Personal 

Imports System.Security 

Imports Microsoft.VisualStudio.TestTools.UnitTesting 

<TestClass()> _ 
Public Class ImpersonationHelperTest 

    Private testContextInstance As TestContext 

    Public Property TestContext() As TestContext 
     Get 
      Return testContextInstance 
     End Get 
     Set(ByVal value As TestContext) 
      testContextInstance = value 
     End Set 
    End Property 

    <TestMethod()> _ 
    Public Sub ImpersonationHelperTest() 

     'testing only, never initialize the characters of the password in this fashion 
     'replace with valid password 

     Dim oPassword As New System.Security.SecureString 

     oPassword.AppendChar("o"c) 
     oPassword.AppendChar("o"c) 
     oPassword.AppendChar("p"c) 
     oPassword.AppendChar("s"c) 
     oPassword.AppendChar("!"c) 
     oPassword.AppendChar(" "c) 
     oPassword.AppendChar("n"c) 
     oPassword.AppendChar("o"c) 
     oPassword.AppendChar(" "c) 
     oPassword.AppendChar("p"c) 
     oPassword.AppendChar("a"c) 
     oPassword.AppendChar("s"c) 
     oPassword.AppendChar("s"c) 
     oPassword.AppendChar("w"c) 
     oPassword.AppendChar("o"c) 
     oPassword.AppendChar("r"c) 
     oPassword.AppendChar("d"c) 

     Using oImpersonation As New ImpersonationHelper("ANTHONY", "amissico", oPassword) 

      oImpersonation.ImpersonateUser() 

      '... 

     End Using 

     Try 

      Using oImpersonation As New ImpersonationHelper("INVALID", "amissico", oPassword) 

       oImpersonation.ImpersonateUser() 

       '... 

      End Using 

     Catch ex As ImpersonationException 
      'expected 
      ' due to invalid domain 
     End Try 


     Try 

      Using oImpersonation As New ImpersonationHelper("ANTHONY", "INVALID", oPassword) 

       oImpersonation.ImpersonateUser() 

       '... 

      End Using 

     Catch ex As ImpersonationException 
      'expected 
      ' due to invalid user 

     End Try 

     Try 

      oPassword.AppendChar(" "c) 'invalidate password 

      Using oImpersonation As New ImpersonationHelper("ANTHONY", "amissico", oPassword) 

       oImpersonation.ImpersonateUser() 

       '... 

      End Using 

     Catch ex As ImpersonationException 
      'expected 
      ' due to invalid password 

     End Try 


    End Sub 

End Class 

Imports System.Security 
Imports System.Runtime.InteropServices 
Imports System.Runtime.CompilerServices 

Public Module SecureStringExtensions 

    ''' <summary> 
    ''' Determines whether the specified <see cref="System.Security.SecureString">System.Security.SecureString</see> instances are considered equal. 
    ''' </summary> 
    ''' <param name="valueA">The first <see cref="System.Security.SecureString">System.Security.SecureString</see> to compare.</param> 
    ''' <param name="valueB">The second <see cref="System.Security.SecureString">System.Security.SecureString</see> to compare.</param> 
    ''' <returns>True if valueA is equal to valueB; otherwise, False.</returns> 
    <Extension()> _ 
    Public Function Equals(ByVal valueA As SecureString, ByVal valueB As SecureString) As Boolean 
     Return IsEqual(valueA, valueB) 
    End Function 

    ''' <summary> 
    ''' Determines whether the specified <see cref="System.Security.SecureString">System.Security.SecureString</see> instances are considered equal. 
    ''' </summary> 
    ''' <param name="valueA">The first <see cref="System.Security.SecureString">System.Security.SecureString</see> to compare.</param> 
    ''' <param name="valueB">The second <see cref="System.Security.SecureString">System.Security.SecureString</see> to compare.</param> 
    ''' <returns>True if valueA is equal to valueB; otherwise, False.</returns> 
    ''' <remarks>Comparison loop based on Microsoft souce code for String.EqualsHelper method.</remarks> 
    <Extension()> _ 
    Public Function IsEqual(ByVal valueA As SecureString, ByVal valueB As SecureString) As Boolean 
     Dim fResult As Boolean = False 'assume failure 

     'short-circuit if lengths are not the same 

     If valueA.Length <> valueB.Length Then 
      'cannot be the same value 
      Return False 
     End If 

     Using oCopyA As SecureString = valueA.Copy, oCopyB As SecureString = valueB.Copy 

      Dim iLength As Integer = oCopyA.Length 

      Dim oPtrA As IntPtr = Marshal.SecureStringToBSTR(oCopyA) 
      Dim oPtrB As IntPtr = Marshal.SecureStringToBSTR(oCopyB) 

      Try 

       Do While (iLength > 0) 

        If Marshal.ReadByte(oPtrA, iLength) <> Marshal.ReadByte(oPtrB, iLength) Then 
         Exit Do 
        End If 

        iLength -= 1 

       Loop 

       fResult = (iLength <= 0) 

      Finally 
       Marshal.ZeroFreeBSTR(oPtrA) 
       Marshal.ZeroFreeBSTR(oPtrA) 

      End Try 

     End Using 

     Return fResult 
    End Function 

End Module 

Imports System.Security 
Imports System.Diagnostics 

Imports Microsoft.VisualStudio.TestTools.UnitTesting 

Imports Missico.Security.SecureStringExtensions 

<TestClass()> _ 
Public Class SecureStringExtensionsFixture 

#Region " TestContext " 

    Private testContextInstance As TestContext 

    Public Property TestContext() As TestContext 
     Get 
      Return testContextInstance 
     End Get 
     Set(ByVal value As TestContext) 
      testContextInstance = value 
     End Set 
    End Property 

#End Region 

    <TestMethod()> _ 
    Public Sub EqualsTest() 

     Dim oValueA As New SecureString 
     Dim oValueB As New SecureString 

     oValueA.AppendChar("p"c) 
     oValueA.AppendChar("a"c) 
     oValueA.AppendChar("s"c) 
     oValueA.AppendChar("s"c) 
     oValueA.AppendChar("w"c) 
     oValueA.AppendChar("o"c) 
     oValueA.AppendChar("r"c) 
     oValueA.AppendChar("d"c) 

     oValueB.AppendChar("p"c) 
     oValueB.AppendChar("a"c) 
     oValueB.AppendChar("s"c) 
     oValueB.AppendChar("s"c) 
     oValueB.AppendChar("w"c) 
     oValueB.AppendChar("o"c) 
     oValueB.AppendChar("r"c) 
     oValueB.AppendChar("d"c) 


     'The Object.Equal method does not work because you cannot compare to secure strings. 

     If oValueA.Equals(oValueB) Then 
      'expected, but does not work 
      'you cannot compare two secure strings 
     Else 
      'always fails 
     End If 


     'Using the fully-qualified path to the Equal extension method. 

     If Missico.Security.SecureStringExtensions.Equals(oValueA, oValueB) Then 
      'expected 
     Else 
      Assert.Fail("SecureString values are not equal, which is not expected.") 
     End If 


     'Using the IsEqual extension method that does not conflict with the Object.Equal method. 

     If oValueA.IsEqual(oValueB) Then 
      'expected 
     Else 
      Assert.Fail("SecureString values are not equal, which is not expected.") 
     End If 


     'change the second value 

     oValueB.AppendChar(" "c) 

     If oValueA.IsEqual(oValueB) Then 
      Assert.Fail("SecureString values are equal, which is not expected.") 
     Else 
      'expected 
     End If 

    End Sub 

End Class 
+0

Ich glaube nicht, aber Sie haben den Code für viele Ihrer Methoden nicht aufgelistet. Trotzdem wird das Passwort in den _password-String kopiert, der GC unterliegt und somit länger als nötig bleiben wird.Der Code, mit dem ich verlinkt bin, pinnt einen verwalteten String im Speicher, so dass er nicht verschoben wird, kopiert das Passwort hinein und wenn es fertig ist, setzt es den Speicher des Strings auf Null. Die Saite bleibt dabei, bis der GC sie sammelt, aber jetzt ist sie auf Null gestellt. Ihr Code tut dies nicht, er setzt nur die nicht verwaltete Zeichenfolge auf Null. – OwenP

+0

Der Link zu "Marshalling SecureString Passwords to String - Mark Nicholson" wurde schließlich angezeigt. – AMissico

+0

Es tut mir leid, dass ich nicht früher zurückkam; Es ist etwas, das ich vergessen habe. Ich kann die Originalseite nicht mehr laden. eine Schande, weil ich denke, dass es einige zusätzliche Bedenken hatte. So wie es aussieht, sieht Ihr Code am ehesten so aus, als ob alle C# -Beispiele, die ich finden kann, in VB .NET aussehen würden. Ich habe eine Sorge, die ich in meine Frage bearbeiten werde, aber ich denke, Sie verdienen das Verdienst, bis jemand eine bessere Lösung finden kann. – OwenP

0

Alle Beispiele die ich gesehen habe nicht berücksichtigt, die Tatsache zu nehmen, dass die Anmeldetyp nicht ein one size fits ist alle Lösung.

Zum Beispiel funktioniert dies nur, wenn der Benutzer, den Sie imitieren, berechtigt ist, sich am Zielsystem anzumelden. Beim Zugriff auf eine Remote-SQL Server-Box nicht immer der Fall. LOGON32_LOGON_INTERACTIVE

NetworkClearText ist das einzige, das konsistent für Verwendung mit SQL Server-Verbindungen funktioniert. - Kein klarer Text bedeutet nicht, dass Anmeldeinformationen in einer unsicheren Weise weitergegeben werden.

Wenn in einer Arbeitsgruppe die Identität eines Domänenbenutzers angenommen werden muss, funktioniert NewCredentials. (Nicht mit SQL Server-Verbindungen getestet)

+2

Willkommen bei Stack Overflow! Seien Sie vorsichtig, wenn Sie kopierte und kopierte Wörter/Verbatim-Antworten auf mehrere Fragen veröffentlichen, diese werden von der Community als "Spam" markiert. Wenn Sie dies tun, bedeutet das normalerweise, dass die Fragen Duplikate sind, also kennzeichnen Sie sie stattdessen als solche. – Kev

0

nur eine Korrektur der Code oben:

die Linie

Dim iLength As Integer = oCopyA.Length 

ist iCorrect. Wie geschrieben wird die Funktion IsEqual nur für die Hälfte + 1 der Zeichen in den Strings testen.

Das muss die richtige Linie sein:

Dim iLength As Integer = oCopyA.Length*2-1 

seit BSTR 2 Bytes pro Zeichen verwendet, und der Index beginnt bei Null, wie üblich. Länge gibt die Anzahl der Zeichen an, nicht die Anzahl der Bytes.

Ansonsten scheint es zu funktionieren.

cignaciob

Grüße

Verwandte Themen