hmm: sqlite

hi leute,

hier mein nodejs server der daten in eine sqlite3 Datenbank schreibt:

app.post('/registrieren', function(req, res) {
    var sqlite3 = require('sqlite3').verbose();
    var db = new sqlite3.Database('skills.db');

    db.serialize(function() {
        db.run("INSERT into user_info(anrede, vorname, nachname, email, passwort) VALUES ('"
        + req.body.Anrede + "', '" 
        + req.body.Vorname + "', '"
        + req.body.Nachname + "', '"
        + req.body.Email + "', '"
        + req.body.Pass
        + "')");
    });

was passiert, wenn sich zwei menschen zeitgleich registrieren? ich hab gelesen, dass immernur eine connection geöffnet sein darf?!?

  1. Nach einer 30-Sekunden-Google-Suche: Der sichere Weg ist, nur eine Verbindung offen zu haben, welche schreibend zugreift.

    Unabhängig davon was darf, es macht doch auch deutlich mehr Sinn, nur eine Verbindung offen zu haben. Also insgesamt jetzt, egal ob lesend oder schreibend.

    Zudem, wenn ich an dein Skript eine Anrede schicke die wie folgt aussieht, hast du Probleme (ohne die Anführungszeichen am Anfang und Ende):
    "', '', '', '', ''); DROP TABLE user_info;"

    1. danke.

      "Zudem, wenn ich an dein Skript eine Anrede schicke die wie folgt aussieht, hast du Probleme (ohne die Anführungszeichen am Anfang und Ende): "', '', '', '', ''); DROP TABLE user_info;""

      hm, du meinst wenn irgendein bösewicht mein htmlformular umgeht und die parameter direkt übergibt? bist du dir sicher das man so einen drop befehl da reinmorksen kann? das würde ja heißen dass das db.run(param) als param zwei sql anweidungen ausführen kann oder?

      also, so wie der server aktuell geschrieben ist. was würde da passieren wenn user A und user B zeitgleich eine registrierung vornehmen?

      würde der rechner dann beide datenbankeinträge nacheinander vornehmen oder würden beide user eine fehlermeldung bekommen? wie mach ich das vernünftig?

      1. Hallo hmm,

        Zudem, wenn ich an dein Skript eine Anrede schicke die wie folgt aussieht, hast du Probleme (ohne die Anführungszeichen am Anfang und Ende):
        "', '', '', '', ''); DROP TABLE user_info;"

        hm, du meinst wenn irgendein bösewicht mein htmlformular umgeht und die parameter direkt übergibt? bist du dir sicher das man so einen drop befehl da reinmorksen kann? das würde ja heißen dass das db.run(param) als param zwei sql anweidungen ausführen kann oder?

        Unter https://github.com/mapbox/node-sqlite3/wiki/API finde ich keinen Hinweis, dass die SQL-Query nur aus einer Anweisung bestehen darf. Das wäre auch sehr eigentümlich bis kontraproduktiv.

        Bis demnächst
        Matthias

        --
        Rosen sind rot.
        1. danke!

          ich hab leider keine ahnung wie ich das verhinderte :(

          angenommen es gäbe die möglichkeit den datenbank zugriff auf nur schreiben und nicht löschen zu beschränken, hätte ich immernoch das problem dass mir jemand den server vollspammt .... wie löst man so ein problem?

          ich hab mal wieder das gefühl, dass ich nur scheiße zusammen code!

      2. Man muss dazu nicht dein HTML-Formular umgehen. Man muss als Anrede einfach obigen Text eingeben. Funktioniert in leicht abgewandelter Art auch mit jedem anderem der Felder.

        Zum Verstehen und Beheben dieser Lücke würde ich dir diesen Artikel zum Kontextwechsel empfehlen.

        Um nicht jedes mal eine neue Verbindung aufzubauen reicht es in deinem Beispiel Zeile 1 zwei weiter runter zu verschieben:

        var sqlite3 = require('sqlite3').verbose();
        var db = new sqlite3.Database('skills.db');
        app.post('/registrieren', function(req, res) {
        
            db.serialize(function() {
                db.run("INSERT into user_info(anrede, vorname, nachname, email, passwort) VALUES ('"
                + req.body.Anrede + "', '" 
                + req.body.Vorname + "', '"
                + req.body.Nachname + "', '"
                + req.body.Email + "', '"
                + req.body.Pass
                + "')");
            });
        });
        

        Falls du aber z.B. in mehreren nodejs dateien die selbe Verbindung verwenden möchtest musst du die irgendwie anderweitig an eben jene durchreichen.

        1. Das würde ich mir gut überlegen. DB-Connections sollte man eigentlich wie heiße Kartoffeln behandeln: Schnappen, reinbeißen, fallen lassen. Nicht permanent offen halten. Ein ordentlicher DB Client mit Connection Pooling leidet deswegen nicht unter Performanzschwäche.

          SQLite als embedded DB mag eine Ausnahme sein, aber zumindest für die Dauer eines Web-Requests würde ich IMMER eine eigene Connection verwenden. Wer weiß, was der letzte Verwender der Connection an Einstellungen hinterlassen hat, mit denen man sich dann ggf. in den Fuß schießt.

          Rolf

      3. Tach!

        Zudem, wenn ich an dein Skript eine Anrede schicke die wie folgt aussieht, hast du Probleme (ohne die Anführungszeichen am Anfang und Ende): "', '', '', '', ''); DROP TABLE user_info;"

        hm, du meinst wenn irgendein bösewicht mein htmlformular umgeht und die parameter direkt übergibt?

        Es ist nicht nur eine Frage der Bösewichte, die diese Lücke gezielt ausnutzen können. Deine Anwendung ist einfach kaputt, wenn man mit bestimmten Eingabewerten SQL-Statements mit Syntaxfehlern erzeugen kann.

        bist du dir sicher das man so einen drop befehl da reinmorksen kann? das würde ja heißen dass das db.run(param) als param zwei sql anweidungen ausführen kann oder?

        Zumindest für den obigen Fall ist das irrelevant, ob sowas geht oder nicht, kaputt ist kaputt. Aber ja, die meisten DBMS lassen das ohne weiteres zu, dass man mehrere Statements gleichzeitig abschicken kann. MySQL ist das einzige mir bekannte System, für das man die Multi-Query-Funktionalität explizit anfordern muss. Bei dem geht also eine SQL-Injection mit zwei Statements im Normalfall nicht durch. Es gibt aber noch genügend Möglichkeiten, sich mit nur einem Statement ungewollte Funktionalität zu verschaffen.

        also, so wie der server aktuell geschrieben ist. was würde da passieren wenn user A und user B zeitgleich eine registrierung vornehmen? würde der rechner dann beide datenbankeinträge nacheinander vornehmen oder würden beide user eine fehlermeldung bekommen? wie mach ich das vernünftig?

        Indem du die Dokumentation des verwendeten Systems (sprich SQLite) studierst.

        dedlfix.

  2. Mein Lösungsvorschlag lautet: Verwende SQLite nicht im Multiuser-Betrieb. Dafür ist es eher nicht gemacht.

    Solange die SQLite-DB nicht über's Netz angesprochen wird (d.h. du gibst de, SQLite-Konstruktur einen Netzwerk-Pfad mit), solltest Du aber halbwegs safe sein. Die beschriebenen Probleme klingen eher danach, als wollte jemand von mehreren Computern gleichzeitig die gleiche DB-Datei verwenden.

    Rolf