Dateihandling auf geschütztem UNC-Pfad

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 25 Antworten in diesem Thema. Der letzte Beitrag () ist von tragl.

    Dateihandling auf geschütztem UNC-Pfad

    Hallo zusammen.

    Ich stehe gerade vor einem größeren Problem:
    Unsere IT hat mir nun endlich einen Speicherplatz im Netzwerk zur Verfügung gestellt, auf dem mein Programm Dateien ablegen darf.
    Das geschieht über das Programm selbst (User können Dateien hinzufügen, löschen, öffnen)
    Aktuell machen wir das pro Standort lokal auf Netzlaufwerken bzw. Netzwerkadressen ohne Zugriffbeschränkung - bzw. der User hat
    durch unsere Domäne automatisch Zugriff darauf -> funktioniert auch einwandfrei.

    Jetzt ist es bei dem "Zentralspeicherplatz" so, dass es einen User und Passwort gibt, den der Anwender nicht kennt. Mein Plan war es
    das im Programm selbst zu hinterlegen, der Anwender bekommt davon nix mit. Somit ist gewährleistet, dass der Anwender nicht einfach
    über den Explorer zu dem Pfad navigiert und sich fremde Dateien anschauen kann.

    Problem:
    Wie stelle ich das mit dem Login an? Ich hätte gerne, dass wenn der Anwender das Programm öffnet, quasi eine Session
    erzeugt wird und das Programm sich an der Freigabe anmeldet (oder meinetwegen bei jeder Dateioperation).

    einfach den Pfad nutzen (z.B. "\\TRAGL-NAS\LogistikToolDev") geht nicht, weil ja anmeldedaten mitgegeben werden müssen.
    Ich hatte dann gerade mal mit Net rumgespielt, komme da aber auch nicht weiter:


    Wäre der Weg über Net generell in Ordnung oder nimmt man hier etwas Anderes? Ich dachte ein UNC-Pfad wäre einfacher,
    als ein CloudStorage in Azure - scheint aber nicht so :(

    PS: ein Netzlaufwerk möchte ich nicht erzeugen - oder wäre das sogar der einfachste weg? Also eins erzeugen, Dateioperation durchführen, netzlaufwerk löschen....
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Ehm, Username/Password im Quellcode ist ein absolutes No-Go!
    Nur so am Rande, der Benutzer kann die Logindaten aus deinem Code auslesen.

    Bezüglich deiner Frage:
    Connect to a UNC Path with Credentials
    @slice: Da ist aber das Problem, dass der User Daten eingeben müsste, die er nicht kennen soll.
    @tragl: Ich habe mit einer Software beruflich das gleiche Problem. Oder besser: Der Hersteller der netwerkfähigen Software hat das gleiche Problem wie Du. Die Software kann sehr viele Dinge, die ein Außenstehender aber ohne Zugangsdaten und ohne die Software nicht aufrufen kann. Der 08/15-User hat von jenen Daten keine Ahnung. Er merkt nur, dass alles klappt, wenn er die Software as-is benutzt. Ich jedoch bin auf der Suche nach API-Funktionen zur Verbesserung jener Software schnell auf die Zugangsdaten gestoßen, die im Code "versteckt" sind. So kann ich mir den Umgang mit jener Software um einiges erleichtern und Verbesserungen vornehmen und eigene Ergänzungsprogramme entwickeln. Aber gewollt war das vom Hersteller sicher nicht. Nur scheint er es auch nicht besser in den Griff bekommen zu haben.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Aus meiner Sicht solltest du deinem Programm eine Zwischenschicht hinzufügen, die die Dateioperationen übernimmt. Das könnte z.B. eine WebAPI sein, die auf einem/dem Server läuft und deine eigentliche Anwendung mit dieser API kommuniziert. Bei dieser API könntest du die Benutzerdaten in einer Konfigurationsdatei hinterlegen - ein Anwender käme so nicht (ohne weiteres) an die Daten.
    Du hast dadurch aber natürlich Mehraufwand bei der Entwicklung und Wartung.
    Hi.

    Ich kann das mit den Credentials auch über die Datenbank lösen - dann kann der User nix aus'm Code auslesen.
    Aber zum testen geht's über Code erstmal schneller. Ich schau' mir die CodeProject-Seite mal an und guck ob
    ich damit was anfangen kann.

    Aber damit wär's unterm Strich ja dann fast egal ob ich nen Netzwerk-Storage mit Credentials nutze (UNC-Pfad) oder
    am Ende sogar auf nen AzureStorage gehe, was vermutlich bei uns die Zukunft sein wird. Man wird sehen ;)
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Wenn du eine Datenbank benutzt, hättest du das Problem immer noch, nur etwas "schoben".
    Deine Anwendung muss eine Verbindung zur Datenbank herstellen, das kann der User ebenfalls auslesen und die Daten dann einfach von Hand aus der Datenbank auslesen.

    Egal wie rum du es drehst, solange der Benutzer nicht eigene Login Daten angibt, wirst du immer ein Problem haben.
    Auch wenn du eine Art API implementierst, die die Daten annimmt, hast du immer noch das Problem, das die API ungeschützt ist.
    Beim SqlServer gibts eine sog. "integrated security" alias "Windows authentication"
    Da kann man inne Datenbank konfigurieren, welcher Windows-Account Zugriff hat.
    Also die Windows-Anmeldung wird als Credentials verwendet, mit denen der User sich angemeldet hat, als er seinen Rechner startete.
    Also der Nutzer muss kein PW eingeben, sondern muss "nur" am richtigen Rechner sitzen.
    Wäre das ein denkbares Modell?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Man kann den Dateien auch elend lange zufällig generierte Namen geben und dann den Ordner in dem diese liegen auf "keine Auflistung" stellen.

    Der User sieht keine Dateien.

    Erst wenn er zufällig eine Datei mit vollständigen Namen komplett aufrufen wird, würde die Datei geöffnet.
    Bei ausreichend langen Namen und kompletten Zeichensatz (also nicht nur Ziffern) ist die Methode so sicher wie die Eingabe eines Passwortes.

    ErfinderDesRades schrieb:

    Wäre das ein denkbares Modell?


    Das wäre für die Zukunft für die Datenbank selbst denkbar, ja.
    Für die Dateien nicht - dann damit kommen die User wiederum auf das Laufwerk und können alles sehen - oder aber es müssen Berechtigungen für jeden User
    auf dem Netzlaufwerk selbst gemacht werden und das sprengt jeglichen Rahmen ;)

    Der flotte Johann schrieb:

    Man kann den Dateien auch elend lange zufällig generierte Namen geben und dann den Ordner in dem diese liegen auf "keine Auflistung" stellen.

    Auch das geht - erschwert aber ggf. administrative Arbeiten enorm.

    Da alles im Firmennetz hängt und ich die Pappenheimer kenne - wird keiner in der Lage sein erst den Login für die Datenbank rauszukriegen und darüber dann die Credentials für das Netzlaufwerk,
    da stelle ich sogar in Frage, ob unsere IT das schaffen würde :P :P
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Auch wenn es nicht mein Thema ist: Wie helfen passwortähnliche Dateinamen in einem quasi ausgeblendeten Ordner weiter? Der Otto-Normal-Programm-Benutzer weiß dann zwar nicht, wo die Dateien liegen/herkommen. Aber Dekompilierung lüftet doch das Geheimnis. Ist doch also so, als ob Zugangsdaten im Code stecken. Oder was übersehe ich/verstehe ich da nicht?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    tragl schrieb:


    PS: ein Netzlaufwerk möchte ich nicht erzeugen - oder wäre das sogar der einfachste weg? Also eins erzeugen, Dateioperation durchführen, netzlaufwerk löschen....


    H3ll0,

    Ruecksprache mit der IT halten waere eine Option, ihr habt bestimmt eine AD, Gruppen erstellen und AD User mit entsprechenden Rechten hinzufuegen.

    Wenn false, gibst andere Optionen wie die den Ansatz schon hattest nennt sich: net use (Ich gehe mal davon aus wir sprechen von µS Umgebung)
    Syntax waere ungefaehr so: net use \\TRAGL-NAS\LogistikToolDev /user:werauchimmer pwwieauchimmer

    dadurch legst du die credentials im systemcache ab ohne ein Laufwerksbuchstaben zu mappen und kannst auf die UNC-Pfade mittels deinem Programm zugreifen.

    Klar User und pw halt noch crypten, damit nicht jeder hexeditor da ran kommt...
    Hi,

    @ATXMega256@32MHz: Net Use hab ich eben getestet - da verlangt er z.B. beim Öffnen des Ordners trotzdem wieder Zugangsdaten
    Ansonsten hab ich das aus dem Link von @slice getestet.

    Auf meinem NAS-Server kam ich mit Zugangsdaten dann dran, hab alles durchprogrammiert. Im Firmennetz auf den Live-Ordner ging dann gar nix.
    Inwzischen hatte ich meinen PC neu gestartet und siehe da - auch da geht nix mehr. Außerdem war es damit scheinbar so, dass die Session sich gemerkt
    wurde, sodass ich auch nach Schließen des Programms noch in dem Ordner rumwühlen konnte.

    Ich bin nun im Gespräch mit der IT - die sollen die Freigabe einfach
    der normalen Benutzergruppe (die es schon für das Programm selbst gibt) zuordnen, diese aber verstecken. Mein Programm kennt die Pfade und Dateinamen
    einen anderen Weg hab ich grad nicht.
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Hängt aber damit zusammen, das du es wahrscheinlich falsch benutzt.
    Du musst am ende Dispose aufrufen oder wie im verlinkten Beispiel ein using-Block, dann wird die Verbindung ordentlich getrennt.

    Bezüglich "zuhause klappts und in der Firma nicht":
    Was klappt denn nicht? Bekommst du eine Fehlermeldung? Benutzt du die richtige Kombination an Zugangsdaten?
    Bei einigen Kunden musste ich den UPN als Benutzername nehmen und keine Domain, bei anderen nur den Benutzernamen + Domain.
    Vollzitat eines Vorposts an dieser Stelle entfernt ~VaporiZed

    Eure Domaene(mit ihrem clients..) unterliegt anderen Policys (zu 100-0,00001% Sicherheitsbedenkter) wie der Bastelbude die du zuHause zum spielen benutzt, logisch das es nicht klappt. Wenn nach einem Windoofrestart die Berechtigungen weg sind, haste wohl den Hacken gesetzt bei "Anmeldedaten merken" oder dem Befehl net use das Argument /savecred mitgegeben.

    Was auch gerne zum scheitern fuehrt ist (meistens) das Ausfuehren eines Programms mit unterschiedlichen Benutzern zur freigegebener Ressource (lokal vs AD user). Da hilft dir dann das Kommando "runas" um dein Problem und die IT zu umgehen. Dein Programm muss unter demselben Benutzerkontext ausgefuehrt werden, wie die Rechte zur freigegebene Netzwerkressource gelegt worden sind.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    Dein Programm muss unter demselben Benutzerkontext ausgefuehrt werden, wie die Rechte zur freigegebene Netzwerkressource gelegt worden sind.
    Nö eben nicht, alles eine Frage wie man es implementiert.
    @slice: Ich habe von Anfang an den Using-Block benutzt
    @ATXMega256@32MHz: bei net use musste ich trotzdem nutzerdaten eingeben, bei der "api" aus dem Link vonv slice gibt's keinen Haken zu setzen. Scheint sich trotzdem in der Session festzusetzen und nach
    einem Neustart ging nix mehr.

    Das das natürlich mit Policy's Betriebsintern zusammenhängt kann gut sein, bin schon im Gespräch mit der IT - die sind allerdings recht wenig an dem Interessiert was ich da mache, sprich die haben keine Lust
    sich damit auseinanderzusetzen und mir zu helfen. Ich muss mal schauen, was die antworten - so geht's jedenfalls leider nicht.

    Zur Not muss es eben Azure Storage oder Sharepoint oder sowas sein - Azure z.B. kann ich privat aber nur begrenzt testen weil man dazu ja ein Abo braucht und das Testabo wird irgendwann ablaufen, davon abgesehen ist es kompliziert
    und ich muss wieder alles umbasteln.
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Du könntest es mal mit einem expliziten Aufruf von Dispose probieren, wie gesagt, bei mir funktioniert das in unzähligen Projekten.
    @slice: Ich hatte mir das mal zu VB.NET übersetzt, damit ich das nicht nur als DLL
    im Projekt hab. Nach meinem Verständnis sollte ein Using-Block automatisch dazu führen, dass am Ende Dispose ausgeführt wird,
    sonst könnte ich doch gar keinen Using-Block nutzen...

    So z.B. nutz ich das:

    VB.NET-Quellcode

    1. Friend Shared Sub CreateDir(DirName As String)
    2. If Not App.StorageAvailable Then Return
    3. Using unc = New UNCAccessWithCredentials()
    4. If EstablishConnection(unc) Then Directory.CreateDirectory($"{Path}\{DirName}")
    5. End Using
    6. End Sub


    VB.NET-Quellcode

    1. Private Shared Function EstablishConnection(unc As UNCAccessWithCredentials) As Boolean
    2. If unc.NetUseWithCredentials(Path, User, "", Pass) Then
    3. Return True
    4. Else
    5. ErrorMessage(unc)
    6. Return False
    7. End If
    8. End Function


    Übersetzung:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Imports DWORD = System.UInt32
    3. Imports LPWSTR = System.String
    4. Imports NET_API_STATUS = System.UInt32
    5. 'Namespace ConnectUNCWithCredentials
    6. Public Class UNCAccessWithCredentials : Implements IDisposable
    7. <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>
    8. Friend Structure USE_INFO_2
    9. Friend ui2_local As LPWSTR
    10. Friend ui2_remote As LPWSTR
    11. Friend ui2_password As LPWSTR
    12. Friend ui2_status As DWORD
    13. Friend ui2_asg_type As DWORD
    14. Friend ui2_refcount As DWORD
    15. Friend ui2_usecount As DWORD
    16. Friend ui2_username As LPWSTR
    17. Friend ui2_domainname As LPWSTR
    18. End Structure
    19. <DllImport("NetApi32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
    20. Friend Shared Function NetUseAdd(ByVal UncServerName As LPWSTR, ByVal Level As DWORD, ByRef Buf As USE_INFO_2, <Out> ByRef ParmError As DWORD) As NET_API_STATUS
    21. End Function
    22. <DllImport("NetApi32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
    23. Friend Shared Function NetUseDel(ByVal UncServerName As LPWSTR, ByVal UseName As LPWSTR, ByVal ForceCond As DWORD) As NET_API_STATUS
    24. End Function
    25. Private disposed As Boolean = False
    26. Private sUNCPath As String
    27. Private sUser As String
    28. Private sPassword As String
    29. Private sDomain As String
    30. Private iLastError As Integer
    31. Private disposedValue As Boolean
    32. ''' <summary>
    33. ''' A disposeable class that allows access to a UNC resource with credentials.
    34. ''' </summary>
    35. Public Sub New()
    36. End Sub
    37. ''' <summary>
    38. ''' The last system error code returned from NetUseAdd or NetUseDel. Success = 0
    39. ''' </summary>
    40. Public ReadOnly Property LastError As Integer
    41. Get
    42. Return iLastError
    43. End Get
    44. End Property
    45. ''' <summary>
    46. ''' Connects to a UNC path using the credentials supplied.
    47. ''' </summary>
    48. ''' <param name="UNCPath">Fully qualified domain name UNC path</param>
    49. ''' <param name="User">A user with sufficient rights to access the path.</param>
    50. ''' <param name="Domain">Domain of User.</param>
    51. ''' <param name="Password">Password of User</param>
    52. ''' <returns>True if mapping succeeds. Use LastError to get the system error code.</returns>
    53. Public Function NetUseWithCredentials(ByVal UNCPath As String, ByVal User As String, ByVal Domain As String, ByVal Password As String) As Boolean
    54. sUNCPath = UNCPath
    55. sUser = User
    56. sPassword = Password
    57. sDomain = Domain
    58. Return NetUseWithCredentials()
    59. End Function
    60. Private Function NetUseWithCredentials() As Boolean
    61. Dim returncode As UInteger
    62. Try
    63. Dim useinfo As USE_INFO_2 = New USE_INFO_2()
    64. useinfo.ui2_remote = sUNCPath
    65. useinfo.ui2_username = sUser
    66. useinfo.ui2_domainname = sDomain
    67. useinfo.ui2_password = sPassword
    68. useinfo.ui2_asg_type = 0
    69. useinfo.ui2_usecount = 1
    70. Dim paramErrorIndex As UInteger
    71. returncode = NetUseAdd(Nothing, 2, useinfo, paramErrorIndex)
    72. iLastError = CInt(returncode)
    73. Return returncode = 0
    74. Catch
    75. iLastError = Marshal.GetLastWin32Error()
    76. Return False
    77. End Try
    78. End Function
    79. ''' <summary>
    80. ''' Ends the connection to the remote resource
    81. ''' </summary>
    82. ''' <returns>True if it succeeds. Use LastError to get the system error code</returns>
    83. Public Function NetUseDelete() As Boolean
    84. Dim returncode As UInteger
    85. Try
    86. returncode = NetUseDel(Nothing, sUNCPath, 2)
    87. iLastError = CInt(returncode)
    88. Return returncode = 0
    89. Catch
    90. iLastError = Marshal.GetLastWin32Error()
    91. Return False
    92. End Try
    93. End Function
    94. Protected Overrides Sub Finalize()
    95. Dispose()
    96. End Sub
    97. Protected Overridable Sub Dispose(disposing As Boolean)
    98. If Not disposedValue Then
    99. If disposing Then
    100. ' TODO: Verwalteten Zustand (verwaltete Objekte) bereinigen
    101. End If
    102. ' TODO: Nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalizer überschreiben
    103. ' TODO: Große Felder auf NULL setzen
    104. disposedValue = True
    105. End If
    106. End Sub
    107. ' ' TODO: Finalizer nur überschreiben, wenn "Dispose(disposing As Boolean)" Code für die Freigabe nicht verwalteter Ressourcen enthält
    108. ' Protected Overrides Sub Finalize()
    109. ' ' Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in der Methode "Dispose(disposing As Boolean)" ein.
    110. ' Dispose(disposing:=False)
    111. ' MyBase.Finalize()
    112. ' End Sub
    113. Public Sub Dispose() Implements IDisposable.Dispose
    114. ' Ändern Sie diesen Code nicht. Fügen Sie Bereinigungscode in der Methode "Dispose(disposing As Boolean)" ein.
    115. Dispose(disposing:=True)
    116. GC.SuppressFinalize(Me)
    117. End Sub
    118. End Class
    119. 'End Namespace
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup: