steckl: Zugriff auf mySql-DB: quotemeta() ausreichend?

Hi,

ich habe ein Loginscript, bei dem der User Namen und Passwort in ein Formular eintraegt und diese Eingaben dann auswertet.

Zur Ueberpruefung hatte ich vorher folgende Anweisungen (etwas vereinfacht):

...
my $login = param('login');
my $query = "select usr_pwd from USERtab where usr_login like '$login' and usr_del='false'";  // query, das spaeter ausgefuehrt wird
...

Jetzt habe ich gemerkt, dass bei Vorkommen von % im login dies als Platzhalter interpretiert wird. Worauf ich das like durch = ersetzt habe.

So war es aber immernoch nicht sicher, da der User bei login ja beispielsweise "' or '1=1" schreiben haette koennen und das Script dann trotzdem korrekt ausgefuehrt worden waere. Noch schlimmer waere es natuerlich, wenn er dort die Datenbank mit update oder insert direkt manipuliert, was bisher wohl auch moeglich gewesen waere.

1. Frage:
Reicht es aus, den String $login mit quotemeta() zu maskieren, oder ist es dann immernoch nicht sicher. Sowohl bei = als auch bei like (wird an anderen Stellen benoetigt).

2. Frage:
Das eingegebene Passwort wird spaeter verschluesselt (mit crypt()) und mit dem ausgelesenen Passwort verglichen, was eigentlich dann wieder sicher sein sollte. Oder kann man ueber das PW auch noch irgendwie "boesen" Code einschleussen?

zugehoeriger Code, falls der login genau einmal gefunden wurde (ansonsten wird gleich eine Fehlermeldung ausgegeben):

...
my $pwFromInput = param('password');
if($pwFromDB eq crypt($pwFromInput,$salt))
{
    # PW war korrekt...
}
else
{
    # PW war inkorrekt...
}

mfG,
steckl

  1. Zur Ueberpruefung hatte ich vorher folgende Anweisungen (etwas vereinfacht):

    ...
    my $login = param('login');
    my $query = "select usr_pwd from USERtab where usr_login like '$login' and usr_del='false'";  // query, das spaeter ausgefuehrt wird

    Damit hast du ein Prima Skript für mysql Injection geschaffen und eröffnest jedem Hacker den zugriff auf deine Datenbanken und deine Anwendung.

    Jetzt habe ich gemerkt, dass bei Vorkommen von % im login dies als Platzhalter interpretiert wird. Worauf ich das like durch = ersetzt habe.

    Der Platzhalter ist gut und sollte auch verwenden werden, dann hast du weder das oben genannte Problem noch eins mit Sonderzeichen:
    http://search.cpan.org/~timb/DBI-1.52/DBI.pm#Placeholders_and_Bind_Values

    So war es aber immernoch nicht sicher, da der User bei login ja beispielsweise "' or '1=1" schreiben haette koennen und das Script dann trotzdem korrekt ausgefuehrt worden waere. Noch schlimmer waere es natuerlich, wenn er dort die Datenbank mit update oder insert direkt manipuliert, was bisher wohl auch moeglich gewesen waere.

    Genau, gut erkannt. wie gesagt google mal nach mysql injection, da wirst du Seiten finden, die genau dieses beschreiben

    Und ein zusätzlicher Tipp: die Doku lesen!

    Struppi.

    --
    Javascript ist toll (Perl auch!)
    1. Hi,

      Damit hast du ein Prima Skript für mysql Injection geschaffen und eröffnest jedem Hacker den zugriff auf deine Datenbanken und deine Anwendung.

      Das hab ich auch gemerkt.
      Zum glück hab ich vor der Freigabe des Projekts nochmal alles durchgeschaut. Diese stelle hatte ich einfach am Anfang übersehen.

      Jetzt habe ich gemerkt, dass bei Vorkommen von % im login dies als Platzhalter interpretiert wird. Worauf ich das like durch = ersetzt habe.

      Der Platzhalter ist gut und sollte auch verwenden werden, dann hast du weder das oben genannte Problem noch eins mit Sonderzeichen:

      http://search.cpan.org/~timb/DBI-1.52/DBI.pm#Placeholders_and_Bind_Values
      Diese Syntax kannte ich bisher nicht, schaut aber recht praktisch aus.
      Aber das hatte ja mit dem Platzhalter so wie er bei mir vorkam eh nichts zu tun.
      Aber bietet das Sicherheitsvorteile gegenüber quotemeta()?

      Genau, gut erkannt. wie gesagt google mal nach mysql injection, da wirst du Seiten finden, die genau dieses beschreiben

      Ich werd mir da mal noch ein paar beispiele anschauen.

      mfG,
      steckl

      1. http://search.cpan.org/~timb/DBI-1.52/DBI.pm#Placeholders_and_Bind_Values
        Diese Syntax kannte ich bisher nicht, schaut aber recht praktisch aus.
        Aber das hatte ja mit dem Platzhalter so wie er bei mir vorkam eh nichts zu tun.
        Aber bietet das Sicherheitsvorteile gegenüber quotemeta()?

        Ja, das das Quoting auf die Bedürfnisse des Datenbanktreibermoduls zugeschnitten ist. DBI arbeitet ja nicht nur mit mysql.

        Struppi.

        --
        Javascript ist toll (Perl auch!)
  2. my $login = param('login');
    my $query = "select usr_pwd from USERtab where usr_login like '$login' and usr_del='false'";  // query, das spaeter ausgefuehrt wird

    Das ist ganz schlimm böse. Nicht nur, dass du Daten von außen ungeprüft im Script weiter verwendest, nein, du baust sie auch noch unbehandelt in ein SQL-Statement ein.

    Jetzt habe ich gemerkt, dass bei Vorkommen von % im login dies als Platzhalter interpretiert wird. Worauf ich das like durch = ersetzt habe.

    Ein LIKE ist nicht nötig, der einfache Vergleich mittels Gleichheitszeichen reicht aus.

    So war es aber immernoch nicht sicher, da der User bei login ja beispielsweise "' or '1=1" schreiben haette koennen und das Script dann trotzdem korrekt ausgefuehrt worden waere. Noch schlimmer waere es natuerlich, wenn er dort die Datenbank mit update oder insert direkt manipuliert, was bisher wohl auch moeglich gewesen waere.

    Ja, dein Code ist hochgradig anfällig für derartige Injections.

    Reicht es aus, den String $login mit quotemeta() zu maskieren, oder ist es dann immernoch nicht sicher. Sowohl bei = als auch bei like (wird an anderen Stellen benoetigt).

    Du kannst dich bei MySQL auf die interne quote-Methode verlassen. Am elegantesten geht das m.E. über Platzhalter:

    my $query = 'SELECT usr_pwd FROM USERtab WHERE usr_login=? AND usr_del=?';  
    my $sth = $dbh->prepare($query)|| die "Preparing statement $stm failed: $DBI::errstr";  
    $sth->execute($login, $status) || die "Executing statement failed: $stm: $DBI::errstr";
    

    my $pwFromInput = param('password');

    Siehe oben.

    Siechfred

    --
    Ich bin strenggenommen auch nur interessierter Laie. (molily)
    1. Hi,

      Das ist ganz schlimm böse. Nicht nur, dass du Daten von außen ungeprüft im Script weiter verwendest, nein, du baust sie auch noch unbehandelt in ein SQL-Statement ein.

      Das hab ich auch gemerkt. Asche über mein Haupt.

      So war es aber immernoch nicht sicher, da der User bei login ja beispielsweise "' or '1=1" schreiben haette koennen und das Script dann trotzdem korrekt ausgefuehrt worden waere. Noch schlimmer waere es natuerlich, wenn er dort die Datenbank mit update oder insert direkt manipuliert, was bisher wohl auch moeglich gewesen waere.

      Ja, dein Code ist hochgradig anfällig für derartige Injections.

      Wenn ich $login = quotemeta($login) einbaue immernoch?
      Falls ja könntest du ein Beispiel nennen, welche Eingabe dann noch zu Fehlern führen würde?

      Du kannst dich bei MySQL auf die interne quote-Methode verlassen. Am elegantesten geht das m.E. über Platzhalter:

      my $query = 'SELECT usr_pwd FROM USERtab WHERE usr_login=? AND usr_del=?';

      my $sth = $dbh->prepare($query)|| die "Preparing statement $stm failed: $DBI::errstr";
      $sth->execute($login, $status) || die "Executing statement failed: $stm: $DBI::errstr";

      Das hat ja Struppi auch vorgeschlagen und scheint sinnvoll zu sein.  
        
        
      
      > > my $pwFromInput = param('password');  
      >   
      > Siehe oben.  
      
      Das versteh ich nicht. Welche Eingabe würde hier zu einem Falschen Verhalten des Programms führen.  
        
      mfG,  
      steckl