DeWitt: SQL: Injections verhindern bei Verwendung von Perl und DBI

Hallo SELFHTML-Gemeinde,

Ich greife mittels Perl und dem DBI-Modul auf eine SQL-Datenbank zu und muss mich folglich auch mit dem Thema SQL-Injections beschäftigen. Wikipedia sagt dazu:

"Das datenbankunabhängige Datenbankmodul DBI unterstützt [zur Verhinderung von SQL-Injections] eine „prepare“-Syntax [...].

  
$statementhandle = $databasehandle->prepare("SELECT spalte1 FROM tabelle WHERE spalte2 = ?");  
$returnvalue = $statementhandle->execute( $spalte2Wert );  

~~~"  
  
Kann ich mit dieser Maßnahme eine über $ENV{'QUERY\_STRING'} ausgelesene Variable unbehandelt in das SQL-Statement einfügen oder sollte ich vorher noch weitere Vorsichtsmaßnahmen beachten?  
  
  
Ciao,  
David //aka DeWitt

-- 
[selfcode](http://community.de.selfhtml.org/fanprojekte/selfcode.htm) ie:% fl:( br:< va:) ls:} fo:| rl:( n4:° ss:) de:] js:| ch:] sh:( mo:| zu:(  
  
<< Life is just a moment in eternity, yet every life echoes there >>
  1. hi,

    Kann ich mit dieser Maßnahme eine über $ENV{'QUERY_STRING'} ausgelesene Variable unbehandelt in das SQL-Statement einfügen oder sollte ich vorher noch weitere Vorsichtsmaßnahmen beachten?

    Prepared-Statements sind schonmal gut. Wenn Du es noch ein bischen sicherer machen möchtest, prüfe auch noch, ob der Value eines Parameters gültig ist.

    Beispiel:
    Es gibt 3 Records, in Spalte 2 stehen die Values 1, 2 und 3.

    Jetzt kommt ein http-Request mit script?col=2 was funktionieren sollte, weil der Wert 2 in Spalte 2 tatsächlich vorkommt.

    Nicht durchgehen sollte ein Request mit script?col=33 weil es den Wert 33 nicht gibt.

    Einfachere aber wirksame Prüfungen könnten sein: Ist der Value numerisch, alphanumerisch usw. Auch damit kannst Du verhinderen, dass jemand einen Code einschleust.

    Viele Grüße,
    Horst Haselhuhn

    1. Einfachere aber wirksame Prüfungen könnten sein: Ist der Value numerisch, alphanumerisch usw. Auch damit kannst Du verhinderen, dass jemand einen Code einschleust.

      Im konkreten Fall geht es um eine email-Adresse, die vor der Weiterverarbeitung mittels eines Regexps überprüft wird, es sollten also eigentlich nur korrekte Daten an SQL übergeben werden. Aber meinen eigenen Sicherheits-Vorkehrungen traue ich nunmal nur bis zu einem gewissen Grad ;).

      --
      selfcode ie:% fl:( br:< va:) ls:} fo:| rl:( n4:° ss:) de:] js:| ch:] sh:( mo:| zu:(
      << Life is just a moment in eternity, yet every life echoes there >>
      1. hi,

        Einfachere aber wirksame Prüfungen könnten sein: Ist der Value numerisch, alphanumerisch usw. Auch damit kannst Du verhinderen, dass jemand einen Code einschleust.

        Im konkreten Fall geht es um eine email-Adresse, die vor der Weiterverarbeitung mittels eines Regexps überprüft wird, es sollten also eigentlich nur korrekte Daten an SQL übergeben werden. Aber meinen eigenen Sicherheits-Vorkehrungen traue ich nunmal nur bis zu einem gewissen Grad ;).

        Genau. Es reicht ja schon, einen String, der als Parameter kommt, auf das Zeichen qq(') zu testen, um zu prüfen, ob der Fuzzi Böses im Schilde führt.

        Viele Grüße,
        Horst Haselhuhn

        1. echo $begrüßung;

          Genau. Es reicht ja schon, einen String, der als Parameter kommt, auf das Zeichen qq(') zu testen, um zu prüfen, ob der Fuzzi Böses im Schilde führt.

          Und damit gibt's für jeden, der beispielsweise O'Brien heißt oder diese Zeichen anderweitig aber 'legal' verwendet erstmal Generalverdacht, nur weil der Programmierer nicht mit seiner Datenbankschnittstelle umgehen kann?

          In einer Email-Adresse sind viel mehr Zeichen erlaubt als landläufig angenommen wird. Sich auf wenige Zeichen zu beschränken, verhindert vielleicht eine SQL-Injection aber keinen Missbrauch. Es gibt keinen RegExp, um zu prüfen, ob die Email-Adresse einem real existierendem Postfach gehört und dessen Besitzer die Verwendung legalisiert hat.

          Das SQL-Injection-Problem muss generell und für alle Arten von Daten gelöst werden. So schwer ist das ja nicht. Notfalls prüft man sein System mit harmlosen selbst erstellten SQL-Injections.

          echo "$verabschiedung $name";

    2. echo $begrüßung;

      Jetzt kommt ein http-Request mit script?col=2 was funktionieren sollte, weil der Wert 2 in Spalte 2 tatsächlich vorkommt.
      Nicht durchgehen sollte ein Request mit script?col=33 weil es den Wert 33 nicht gibt.

      Wie prüfst du das Nicht-Vorhandensein, wenn du aus Sicherheitsbedenken nicht die Datenbank befragen kannst, ob dieser Wert enthalten ist oder nicht?

      echo "$verabschiedung $name";

  2. echo $begrüßung;

    "Das datenbankunabhängige Datenbankmodul DBI unterstützt [zur Verhinderung von SQL-Injections] eine „prepare“-Syntax [...].
    Kann ich mit dieser Maßnahme eine über $ENV{'QUERY_STRING'} ausgelesene Variable unbehandelt in das SQL-Statement einfügen oder sollte ich vorher noch weitere Vorsichtsmaßnahmen beachten?

    Bei Prepared Statements werden keine Daten in das Statement eingefügt. Deshalb muss da auch weder was quotiert noch maskiert werden. Das Statement mit den Platzhaltern und die Daten gehen getrennte Wege zum DBMS. Wenn DBI die Prepared Statements nur simuliert, dann ist es selbst dafür verantwortlich, die Daten korrekt in das Statement einzusetzen.

    Wenn du allerdings keinen Platzhalter verwendest, sondern selbst veränderliche Daten in das Statement einfügen möchtest, dann ist das zum einen eine schlechte Idee, und hat zum anderen zur Folge, dass du dich wieder selbst um die korrekte Notation kümmern musst.

    echo "$verabschiedung $name";

  3. $statementhandle = $databasehandle->prepare("SELECT spalte1 FROM tabelle WHERE spalte2 = ?");
    $returnvalue = $statementhandle->execute( $spalte2Wert );

    
    >   
    > Kann ich mit dieser Maßnahme eine über $ENV{'QUERY\_STRING'} ausgelesene Variable unbehandelt in das SQL-Statement einfügen oder sollte ich vorher noch weitere Vorsichtsmaßnahmen beachten?  
      
    Fragst Du, ob Du als $spalte2Wert durchaus auch "1;delete from tabelle" übergeben kannst, ohne daß er tabelle löscht?  
      
    Darauf kann man mit ja antworten. Wenn nicht ist es ein Bug in dem verwendeten DBD Modul.  
      
    Wenn Du allerdings fragst, ob $statementhandle->execute( 2 ) erfolgreich ausgeführt werden kann, so lautet die Antwort: it depends.  
      
    Ob Du nach 2 in spalte2 fragen kannst, oder nach "2" fragen mußt, hängt von der Tabellendefinition ab. Manche DBD Module wandeln die Zahl 2 auch automatisch in den String "2" um, wenn die Datenbank das so will, oder auch umgekehrt. Das tun aber nicht alle.
    
    1. Fragst Du, ob Du als $spalte2Wert durchaus auch "1;delete from tabelle" übergeben kannst, ohne daß er tabelle löscht?

      Darauf kann man mit ja antworten. Wenn nicht ist es ein Bug in dem verwendeten DBD Modul.

      Genau das meine ich. Im konkreten Fall geht es um die Abmeldung eines Newsletter, die über eine URL der Form unsubscribe.htm?email=my@mail.tld aufgerufen wird. Ich weiß, diese Lösung ist trotz gegebener Sicherheit von seiten SQL nicht ideal, aber für das aktuelle Problem bleiben mir leider wenig Alternativen.

      Wenn Du allerdings fragst, ob $statementhandle->execute( 2 ) erfolgreich ausgeführt werden kann, so lautet die Antwort: it depends.

      Ja, wenn dabei Fehler entstehen, werden diese abgefangen und ausgeben.

      Danke für alle Antworten!

      Ciao,
      David //aka DeWitt

      --
      selfcode ie:% fl:( br:< va:) ls:} fo:| rl:( n4:° ss:) de:] js:| ch:] sh:( mo:| zu:(
      << Life is just a moment in eternity, yet every life echoes there >>