Aktuelles Thema: Serial überprüfen mit MySQL

  • Hi ihr,

    habe jetz doch schnell was gebaut, mit dem man "Serials" mit Hilfe von ner MySQL-Datenbank überprüfen kann.
    Die Tabelle hat nur eine Spalte mit Datentyp "varchar(20)" (nehmt, was ihr wollt!) und ansonsten dürfts auch selbsterklärend sein.
    Ob ihr ne Serial aus den Hardware-IDs oder (wie ich) aus @UserProfileDir was verschlüsseltes generiert oder was ganz anderes nehmt, bleibt euch überlassen.

    Es funktioniert übrigens :thumbup:

    Spoiler anzeigen
    [autoit]

    #include <mysql.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global $serial = FileRead(@ScriptDir & "\serial.txt")

    [/autoit] [autoit][/autoit] [autoit]

    If sqlcon($serial) Then
    MsgBox(64, "OK", "Richtiger Key!")
    Exit
    Else
    MsgBox(16, "Error", "Falscher Key!")
    Exit
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Func sqlcon($search)
    Local $out
    Local $result = False
    Local $sqluser = "root" ;sql user
    Local $sqlpass = "" ;sql pass
    Local $sqldb = "serials" ;datenbank
    Local $sqltable = "serials" ;tabelle
    Local $sqlserv = "192.168.10.2" ;sql server
    Local $sqlcon = _MySQLConnect($sqluser, $sqlpass, $sqldb, $sqlserv)
    Local $read = _Query($sqlcon, "SELECT * FROM " & $sqltable)
    With $read
    While Not .eof
    $out = .fields("number" ).value
    If $out == $search Then $result = True
    .movenext
    WEnd
    EndWith
    _mysqlend($sqlcon)
    Return $result
    EndFunc ;==>sqlcon

    [/autoit]

    P.S.: Die "serial.txt" könnte man auch in die Registry auslagern oder sonst irgendwohin, ging so nur am Schnellsten :)

    Simon nörgelt, Simon nervt - aber Simon verbessert die Welt. Glaubt er.

    2 Mal editiert, zuletzt von x0r (4. September 2013 um 12:39)

  • Warum lässt du alle Keys auslesen und erst dann einzeln von AutoIt vergleichen?
    Je mehr Keys in der Datenbank stehen umso langsamer wird das ganze.
    Besser wäre es die Überprüfung direkt von MySQL durchführen zu lassen.
    Also z.B. so:

    [autoit]

    _Query($sqlcon, "SELECT COUNT(*) FROM serials WHERE number='" & $serial & "';")

    [/autoit]


    Das hätte zusätzlich den Vorteil, dass die korrekten Serials nie auf den Rechner gelangen und dort ausgelesen werden könnten.

    Allerdings könnte man dann eine Serial immer als richtig deklarieren wenn man z.B. einfach in die serial.txt folgendes schreibt:

    Code
    xyz' OR 1=1


    Da wären wir nämlich schon beim nächsten Problem.
    Der User hat volle Rechte auf Selects - und damit kann er die korrekten Keys abfragen und/oder die dynamischen Abfragen per SQL-Injection austricksen (wie eben demonstriert).
    Die eindeutig bessere Lösung wäre es daher auf dem MySQL-Server einen Nutzer zu erstellen welcher lediglich Rechte auf "Call" (müsste über das Privileg "Execute" gehen) erhält.
    Dessen Zugangsdaten können dann völlig unbedenklich im AutoItskript untergebracht werden.
    Dann erstellt man sich auf dem Server noch folgende Prozedur:

    SQL
    CREATE PROCEDURE check_serial(IN UserSerial	VARCHAR(20))
    	SELECT COUNT(*) FROM serials WHERE number=UserSerial;


    Als Abfrage im AutoItskript verwendet man dann noch lediglich folgendes:

    [autoit]

    _Query($sqlcon, "Call check_serial('" & $serial & "');")

    [/autoit]


    Dann wird das ganze performant, SQL-Injections werden verhindert, und der User hat keine Möglichkeit mehr auf die korrekten Serials zuzugreifen.
    Die einzige Sicherheitslücke besteht dann nur noch in der Veränderung des AutoItskriptes. Auf Datenbankseite ist dann hingegen alles sicher.

    Einmal editiert, zuletzt von AspirinJunkie (4. September 2013 um 13:20)

  • Ich würde die MySql Daten nie in ein Programm schreiben.
    Lieber würde ich es in einer Datei auslager, also ein POST Request an eine Datei senden die dir sagt ob der Key verfügbar ist oder nicht.

  • Ich würde die MySql Daten nie in ein Programm schreiben.


    Kommt auf die Rechte des Nutzers an.
    Wenn man mit dem eingetragenen User lediglich, wie hier vorgeschlagen, z.B. nur CALL ausführen kann sehe ich kein gravierendes Problem dabei.
    Dann verhält es sich nämlich genauso wie du vorgeschlagen hast.


  • Dann erstellt man sich auf dem Server noch folgende Prozedur:

    SQL
    CREATE PROCEDURE check_serial(IN UserSerial	VARCHAR(20))
    	SELECT COUNT(*) FROM serials WHERE number=UserSerial;


    Als Abfrage im AutoItskript verwendet man dann noch lediglich folgendes:

    [autoit]

    _Query($sqlcon, "Call check_serial('" & $serial & "');")

    [/autoit]


    Dann wird das ganze performant, SQL-Injections werden verhindert

    Sicher? Wer hindert mich daran SQL Code über deine "UserSerial" IN Variable in die Prozedur einzuschleusen?

    Haben Prozeduren in MySQL überhaupt einen Rückgabewert oder sollte das nicht eher eine stored function sein?

  • Sicher? Wer hindert mich daran SQL Code über deine "UserSerial" IN Variable in die Prozedur einzuschleusen?

    Eine Prozedur (und auch eine Funktion) werden im Server "kompiliert". Die Variablen bekommen dabei einen festen Datentyp (hier einen String).
    Bei der Ausführung wird kein SQL-Code mehr geparst. Die Variablen werden dabei direkt entsprechend ihrem Typ in den Code eingefügt.
    Daher bringt eine SQL-Injection hierbei nichts.
    Wenn man allerdings dynamisches SQL in der Prozedur verwendet dann kann man durchaus noch SQL-Injections unterbringen.
    Das ist hier aber nicht der Fall.

    Haben Prozeduren in MySQL überhaupt einen Rückgabewert oder sollte das nicht eher eine stored function sein?

    Die Prozedur gibt nichts zurück.
    Sie löst lediglich ein Select Statement aus.
    Aber prinzipiell könnte man durchaus statt der Prozedur eine Funktion schreiben welche direkt nur ein True oder False zurück gibt.
    €dit: Für Funktionsaufrufe benötigt man Rechte auf SELECT - das wollen wir hier aber eigentlich vermeiden.


    Edit: Ich hab mal ein solches System umgesetzt (liegt im Anhang).
    Es prüft Name-Seriennumer-Kombinationen. Die Seriennummer muss dabei einer 20stelligen Zahl entsprechen.
    Statt der direkten Daten werden in der Datenbank aber lediglich die Hashes gespeichert.
    So ist sichergestellt, dass ein Auslesen der Datenbank keine Rückschlüsse auf gültige Kombinationen zulässt.

    Auf dem Server muss erst die Datenbank und der Benutzer so erstellt werden wie in der CreateLicenseDB.sql angegeben.
    Dort ist auch beschrieben wie man neue Name-Seriennummer-Kombinationen in die Datenbank einträgt.
    Die zu prüfende Seriennummer liegt dann in der Datei "Lizenz.lic".

    Durch den Aufbau der Datenbank und den beschränkten Userrechten sollte das System auf Datenbankseite sicher sein.
    Lediglich durch Manipulation des AutoItskriptes oder des Kommunikationsweges zwischen Client und Server kann man die Überprüfung noch austricksen.
    Wenn gültige Seriennummern im Umlauf sind, kann man diese einfach durch Entfernen in der Datenbank ungültig machen.
    Zur Erweiterung könnte man noch für jede Hash den letzten Zugriff loggen und die Anzahl der Aufrufe um somit eine illegale Benutzung eines Keys von zu vielen Benutzern aufzudecken.