SQLight Sicherheit und Codeanalysen

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

Es gibt 35 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    @DTF

    Danke, aber ich habe das Problem ja nicht bei einer "Select" Abfrage sondern hier:

    VB.NET-Quellcode

    1. ​Using command As New SQLiteCommand(query, connection)

    Wie ich es auch drehe und wende, es scheitert immer an dieser Zeile.

    VB.NET-Quellcode

    1. Public Sub LoadTableColumns(tableName As String)
    2. Con2DataBase()
    3. Dim columnList As New List(Of String)()
    4. Dim query As String = $"PRAGMA table_info({QuoteIdentifier(tableName)})"
    5. Debug.WriteLine($"Class: {query}")
    6. Using command As New SQLiteCommand(query, connection)
    7. Using reader As SQLiteDataReader = command.ExecuteReader()
    8. While reader.Read()
    9. Dim columnName As String = reader("name").ToString()
    10. columnList.Add(columnName)
    11. End While
    12. End Using
    13. End Using
    14. CloseConnection()
    15. RaiseEvent ColumnsLoaded(columnList)
    16. End Sub
    17. Private Function QuoteIdentifier(identifier As String) As String
    18. ' Funktion zum Sicheren Umgeben von Tabellen-/Spaltennamen mit Anführungszeichen
    19. Return $"`{identifier.Replace("`", "``")}`"
    20. End Function


    Auf dem Form wo die Tabelle ausgwählt wird.

    VB.NET-Quellcode

    1. Private Sub ListBoxTables_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBoxTables.SelectedIndexChanged
    2. If ListBoxTables.SelectedItem IsNot Nothing Then
    3. DBConnection.SelectedTable = ListBoxTables.SelectedItem.ToString()
    4. Debug.WriteLine($"Form: {DBConnection.SelectedTable}")
    5. ' Weitere Verarbeitung oder Aufruf anderer Methoden
    6. DBConnection.LoadTableColumns(DBConnection.SelectedTable)
    7. End If
    8. End Sub
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Also wo liegt denn jetzt genau das Problem? Nur die TableInfo zu bekommen? Tablenamen funktionieren ja nicht NamedParam. Wenn es dir nur um die TableInfo geht, geht das so wie folgt. Der Tablename muss in SingleQoutes verpackt sein, die selben die du in VB für Kommentare nimmst.

    C#-Quellcode

    1. //SqliteConnection DbConnection = new SqliteConnection($"Data Source = filename.db");
    2. //DbConnection.Open();
    3. private void PragmaTableInfo(string tableName)
    4. {
    5. using (SqliteCommand command = DbConnection.CreateCommand())
    6. {
    7. command.CommandText = $"PRAGMA table_info('{tableName}')";
    8. using (SqliteDataReader reader = command.ExecuteReader())
    9. {
    10. for (int i = 0; i < reader.FieldCount; i++)
    11. {
    12. Debug.WriteLine(reader.GetName(i));
    13. }
    14. }
    15. }
    16. }


    PS:
    Da der Tablename ja nicht aus Userinput stammt, ist ja keine Injection möglich an der Stelle. Sqlite ist auch nur eine lokale DB, wenn da ein User eine Injection macht und alles weg ist, auch egal, sind ja seine Daten. Anders ist es wenn die DB öffentlich erreichbar ist, ich meine keinen Direktzugriff, das würde ich niemals gestatten, sondern mit einer "Zugriffsschicht" z.B. mit PHP realisiert. Dann hast du alles zu machen was geht um Injections zu vermeiden. Klar kannste auch Sqlite so öffentlich zugänglich machen, aber dafür gibt es besseres.(Postgre SQL ist aktuell mein Favorit)
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „DTF“ ()

    @DTF

    Der Code auch aus dem Ersten Beitrag funktioniert!
    Ich bekomme aber diese Meldung:

    ​Warnung CA2100 Die in 'DBConnection.LoadTableColumns(String)' an 'SQLiteCommand.CommandText.Set(String)' übergebene Abfragezeichenfolge könnte die folgenden 'DBConnection.QuoteIdentifier(tableName)'-Variablen enthalten.

    Die ist nicht wegzubekommen!
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Du kannst das ja mal so versuchen, statt den Tablename der Sub zu übergeben, übergibst du die Query:

    VB.NET-Quellcode

    1. Public Sub LoadTableColumns(query As String)
    2. ' Zur DB verbinden und öffnen
    3. Con2DataBase()
    4. Dim columnList As New List(Of String)()
    5. Using command As New SQLiteCommand(connection)
    6. command.CommandText = query

    Dann ist der Subaufruf nicht LoadTableColumns("meineTabelle"), sondern LoadTableColumns("PRAGMA table_info('meineTabelle')").
    Und da gibts dann auch keine Variable zu finden, über die er meckern kann.

    --------------
    Bzw. probier vorher mal New SQLiteCommand(query, connection) in deiner ursprünglichen Version, statt CommandText nachträglich zu setzen.

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

    Es bring nichts, die Meldung geht nicht weg.
    Habe sogar mit einem nochmaligen komplett neuem Project versucht. Nun ist egal, dann muss ich damit leben.
    Danke
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:

    Amelie schrieb:

    dann muss ich damit leben.


    Warnungen sind nur Warnungen, keine Fehler. Soll jetzt nicht heissen, das man Warnungen grundsätzlich ignorieren kann. Aber so einige Warnungen kann man ignorieren, solange man sich sicher ist was man tut. Hin und wieder muss man das auch absichern. Hier bist du die Person die den Tabellennamen angibt, nicht der User(Never trust User-Input). Somit kannst du dir auch die Funktion zum replacen sparen und schon wäre die Warnung weg.

    Sqlite wird im normal angewendet um lokal Daten zu speichern, man braucht keinen Datenbankserver. Somit ist die Datenbank nicht öffentlich zugänglich(eine Direktverbindung sollte man dann eh meiden), immer eine Zugriffsschicht dazwischen haben. Somit sind es meist Daten vom User selbst. Wenn dieser nun meint eine Injection zu probieren, sind seine eigenen Daten weg, wenn kein Backup gemacht wurde. Deshalb sehe ich hier auch keinen Grund jedes Luftloch zuspachteln zu müssen damit es Wasserdicht ist.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    DTF schrieb:

    Deshalb sehe ich hier auch keinen Grund jedes Luftloch zuspachteln zu müssen damit es Wasserdicht ist.
    Aber IMO wäre schon recht wichtig, ob es Amelie überhaupt gelingt, eine parametrisierte Abfrage an SqLite abzufahren.
    Zum einen um zu verifizieren, das SqLite das grundsätzlich kann (wenn auch nicht in diesem PRAGMA-Ausdruck).
    Zum andern, wenn Amelie mal an eine richtige Db geht, dass sie dann nicht gezwungen ist, unverantwortlichen Bockmist zu coden.
    Wie es soweit aussieht kann sie das ja bereits.(Denke ich zumindest) Wobei ein wenig üben ist nicht falsch. @Amelie Wenn du das mit Sqlite soweit hinbekommen hast, kann ich dir mal empfehlen PostgreSQL zu installieren. Das ist dann eine "richtige" Datenbank. MySQL wäre auch ein Versuch wert, aber da hab ich die Erfahrung gemacht, das sich einige schwer damit tun den Server richtig aufzusetzen und dann auch zu nutzen. PostgreSQL hat auch den Vorteil, das direkt eine GUI dabei ist, mit der du die DBs bearbeiten kannst, was bei MySQL nicht der Fall ist.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

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

    Tja - vlt habich was übersehen. Aber ich erinner mich an keinem Code von Amelie, der eine parametrisierte Db-Abfrage durchführt, von der sie sagt, dasses funzt.
    Und falls sie das nicht kann, wird das mit grosser Wahrscheinlichkeit (kann natürlich auch sein, dass nicht...) zu unverantwortlichen Sicherheitslücken führen, falls sie mal was für andere Nutzer als sich selbst codet.
    Ich glaub, da hab ich was durcheinander gebracht. Dachte das hätte Amelie bereits, aber Amelie kann einmal hier gucken und damit probieren, falls sie denn spicken möchte:
    SQLight Sicherheit und Codeanalysen

    Weil Amelie auf meinen Post mit dem Code schrieb
    Danke, aber ich habe das Problem ja nicht bei einer "Select" Abfrage sondern hier:


    ging ich davon aus, das dies schon klappt. Zum üben könnte @Amelie auch noch beim hinzufügen der Parameter den Datentyp reinmachen. Gibt ja noch andere überladungen, das könnte sie eines Tages evtl. auch brauchen.

    Auch ein wenig besser machen, das hier meine ich:
    reader("name").ToString()

    Stattdessen reader.GetOrdinal um den ColumnIndex zu bekommen, und dann mit reader.GetValue(INDEX) den Wert holen.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

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

    Moin moin

    Hier mein letzter Versuch das in den Griff zu bekommen. Die Warnung bleibt bestehen. :(



    Spoiler anzeigen

    Das Form:

    VB.NET-Quellcode

    1. Public Class FrmMain
    2. Public Sub New()
    3. InitializeComponent()
    4. End Sub
    5. Private Sub FrmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    6. Dim tableNames As List(Of String) = DBConnection.LoadTables()
    7. ListBoxTables.DataSource = tableNames
    8. End Sub
    9. Private Sub ListBoxTables_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBoxTables.SelectedIndexChanged
    10. LoadColumnsForSelectedTable()
    11. End Sub
    12. Private Sub LoadColumnsForSelectedTable()
    13. If ListBoxTables.SelectedItem IsNot Nothing Then
    14. DBConnection.SelectedTable = ListBoxTables.SelectedItem.ToString()
    15. Dim selectedTableName As String = ListBoxTables.SelectedItem.ToString()
    16. Dim query As String = $"PRAGMA table_info({DBConnection.QuoteIdentifier(selectedTableName)})"
    17. Dim columnsList As List(Of String) = DBConnection.LoadTableColumns(query, "@selectedInput", selectedTableName)
    18. ListBoxCategory.DataSource = columnsList
    19. End If
    20. End Sub
    21. End Class


    Das Modul:

    VB.NET-Quellcode

    1. Module DBConnection
    2. Private connection As SQLiteConnection
    3. Private ReadOnly DataBaseName As String = "northwindEF.db"
    4. Private _selectedTable As String
    5. Sub New()
    6. Con2DataBase()
    7. End Sub
    8. Private Sub Con2DataBase()
    9. Dim databasePath As String = Path.Combine(Application.StartupPath, DataBaseName)
    10. Dim connectionString As String = $"Data Source={databasePath};Version=3;"
    11. connection = New SQLiteConnection(connectionString)
    12. connection.Open()
    13. End Sub
    14. Sub CloseConnection()
    15. If connection IsNot Nothing AndAlso connection.State = ConnectionState.Open Then
    16. connection.Close()
    17. End If
    18. End Sub
    19. Public Property SelectedTable As String
    20. Get
    21. Return _selectedTable
    22. End Get
    23. Set(value As String)
    24. _selectedTable = value
    25. End Set
    26. End Property
    27. Public Function QuoteIdentifier(identifier As String) As String
    28. Return $"`{identifier.Replace("`", "``")}`"
    29. End Function
    30. Public Function LoadTables() As List(Of String)
    31. Dim tableNames As New List(Of String)()
    32. Using command As New SQLiteCommand("SELECT name FROM sqlite_master WHERE type='table' AND name <> 'sqlite_sequence'", connection)
    33. Using reader As SQLiteDataReader = command.ExecuteReader()
    34. While reader.Read()
    35. Dim tableName As String = reader("name").ToString()
    36. tableNames.Add(tableName)
    37. End While
    38. End Using
    39. End Using
    40. CloseConnection()
    41. Return tableNames
    42. End Function
    43. Public Function LoadTableColumns(query As String, ByVal parameterName As String, ByVal parameterValue As Object) As List(Of String)
    44. Con2DataBase()
    45. Dim columnList As New List(Of String)()
    46. Using command As New SQLiteCommand(query, connection)
    47. command.Parameters.AddWithValue(parameterName, parameterValue)
    48. Using reader As SQLiteDataReader = command.ExecuteReader()
    49. While reader.Read()
    50. Dim columnName As String = reader("name").ToString()
    51. columnList.Add(columnName)
    52. End While
    53. End Using
    54. End Using
    55. CloseConnection()
    56. Return columnList
    57. End Function
    58. End Module

    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    sag bescheid, wenn du lernen möchtest, parametrisierte DbCommands zu verwenden.
    Dass die PRAGMA-Anweisung dafür nicht geeignet ist, hat sich ja nu herauskristallisiert.
    Das ist aber auch eine sehr ungewöhnliche Abfrage - normalerweise kennt man die Spalten der DbTabelle ja bereits.

    Also mit anderen Abfragen könntest du lernen, parametrisierte DbCommands zu verwenden.
    Also um ein bissel mehr Licht ins dunkel zu bringen, auch was das "lernen" betrifft.

    Ich habe mal ein kleines Tool für meinen Opa geschrieben. Läuft auf seinem Laptop ( meist ohne Internet ) Dieses Tool basiert auf vielen XML-Dateien und ist, sagen wir mal so, sehr zusammengestückelt, keine Klassen, kein OOP usw. Davon wollte ich nun ein "Rebuild" mit Datenbank usw. schreiben.

    Begonnen hatte ich dann mit Access 2003 weil das bei Opa auf dem Laptop läuft und die Anbindung an VB.net einfach ist. Dann kam der große "Knackpunkt" das ganze ginge dann nur mit 32Bit.
    Also als alternative ohne ins System einzugreifen, war dann "SQLight". Die GUI dazu finde ich etwas seltsam und tue mich echt schwer da die DB / Tabellen und Beziehungen zu erstellen. Dann ist die Anbindung an VB auch nicht so einfach. Also das mit dem Designer DT / DS usw.. Ich wollte mir aber auch nicht gleich wieder haufenweise neue Sachen von "NuGet" installieren, die im Moment noch nicht in meinen Skill passen.

    Das mit der Codeanalyse wollte ich halt machen, um zu sehen, ob das mit meinem "CleanCode" usw nun besser geworden ist.
    Danke
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:

    Amelie schrieb:

    ob das mit meinem "CleanCode" usw nun besser geworden ist.
    • ConToDatabase() kann weg - der Code sollte in Sub New ausgeführt werden, ausser: connection.Open(). Das sollte da aufgerufen werden, wo die connection geöffnet werden soll.
    • CloseConnection() kann weg - stattdessen reicht der direkte Aufruf: connection.Close().
    • Wozu Property SelectedTable erforderlich ist ist nicht ersichtlich.
    • LoadTableColumns() führt eine beliebige Query aus - macht somit etwas ganz anderes als die Function heisst.
    • Würde LoadTableColumns() mit einem geeigneten Query-String aufgerufen, so würde sie ein parametrisiertes Command mit einem Parameter ausführen.
      Wird aber mit einem ungeeigneten Query-String (ohne Parameter-Platzhalter) aufgerufen, also macht nochmal was anderes, als man anderes denkt, was beabsichtigt sein könnte.

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