2011-12-05 27 views
1

mysqlの.netコネクタを使用しています。私は、正しく動作するようだが、有効なログインの詳細でログインボタンをクリックすると、私は正常にログインしたことを教えて、間違ったユーザー/パスのコンボを教えてくれました。複数のelse文が正しく動作しない場合

ここにコードがあり、すべてがそうであるように思われます。

ハッシュされたパスワードがデータベースに入力されたものと一致しているかどうかをチェックします。しかし、何らかの理由で「正常にログインしました」というメッセージボックスが表示された直後に、「間違ったユーザー名とパスワードの組み合わせ」というメッセージボックスが表示されます。

私は過去2日間、どこに間違っていたのか、そしてそのドライビングナットは何かを見つけようとしてきました。私が台無しどこ多分皆さんは見ることができ笑

コード:

  try 
     { 
      MySqlConnection connection = new MySqlConnection(MyConString); 
      MySqlCommand command = connection.CreateCommand(); 
      MySqlDataReader Reader; 
      command.CommandText = "select * from users"; 
      try 
      { 
       connection.Open(); 
      } 
      catch (Exception ex) 
      { 
       listBox4.Items.Add(ex); 
       MessageBox.Show("There has been an error connecting to the user database! Please try again later."); 
      } 
      Reader = command.ExecuteReader(); 
      while (Reader.Read()) 
      { 
       if (textBox4.Text == Reader.GetString(2)) 
       { 
        string haspass= CryptorEngine.Encrypt(textBox5.Text, true); 
        if (haspass == Reader.GetString(3)) 
        { 
          MessageBox.Show("Successfully logged in!"); 
        } 
        else 
        { 
         MessageBox.Show("Wrong Unhashed Username/Password Combination"); 
        } 
       } 
       else 
       { 
        MessageBox.Show("Wrong Username/Password Combination"); 
       } 
      } 
      connection.Close(); 
     } 
     catch (Exception ex) 
     { 
      listBox4.Items.Add(ex); 
     } 
+0

なぜSQLクエリ( 'where句)でフィルタリングをしないのですか? 'reader 'を使って返される行の数を確認することができます。HasRows' – Nasreddine

+0

いいえ。最初のifステートメントは、ユーザー名がデータベースに存在するかどうかをチェックし、存在する場合はパスワードをチェックします。ユーザー名が存在しない場合は、「間違ったユーザー名とパスワードの組み合わせ」というメッセージが表示されます –

+0

'select *によってユーザーから返されたものは? – sll

答えて

3

はそれを行うには良い方法だ:

try 
{ 
    MySqlConnection connection = new MySqlConnection(MyConString); 
    MySqlCommand command = connection.CreateCommand(); 
    MySqlDataReader Reader; 
    //Change the "username" and "password" to the corresponding names of these columns in your table 
    command.CommandText = "SELECT * FROM users WHERE username = @username AND password = @password LIMIT 1"; 
    //assuming textbox4 has the username 
    command.Parameters.AddWithValue("@username", textBox4.Text); 
    command.Parameters.AddWithValue("@password", CryptorEngine.Encrypt(textBox5.Text, true)); 

    try 
    { 
     connection.Open(); 
    } 
    catch (Exception ex) 
    { 
     listBox4.Items.Add(ex); 
     MessageBox.Show("There has been an error connecting to the user database! Please try again later."); 
     //you should return here since if there's no connection you can't run the query 
    } 

    Reader = command.ExecuteReader(); 

    if(Reader.HasRows){ 
     MessageBox.Show("Successfully logged in!"); 
    } 
    else 
    { 
     MessageBox.Show("Wrong Username/Password Combination"); 
    } 

    connection.Close(); 
} 
catch (Exception ex) 
{ 
    listBox4.Items.Add(ex); 
} 

これは一つだけを返します。行(存在する場合)。

+0

はい、それでもテーブル全体がスキャンされます。 'LIMIT'と組み合わされた' EXISTS'節を使用して、最初に利用可能な結果のみを返す方が良いでしょう。 –

+0

@IoannisKaradimas「LIMIT」については知っていますが、「EXISTS」についてはわかりません。また、提案のおかげで、私は 'LIMIT'でソリューションを更新しました。 – Nasreddine

+0

私の記事には説明が追加されていますが、ソース(MySQLリファレンス資料へのリンク)に行くほうがよいでしょう。乾杯! –

4

あなたDataReaderが複数の結果を返している場合、コードはその後、最初の結果のために成功したパスに落ちるように見えます2番目の結果のパスが正しくありません。

あなたが代わりにあなただけのまま現在ログイン中にしようとしているユーザーの詳細を照会する必要がありselect * from usersすべてのユーザーに対して照会を、あなたのSQLは、より具体的にする必要があり、(擬似コード)のようなもの -

select * from users where username = yourusernamefield

ここで、yourusernamefieldの値はフォームから取得されました。ユーザー名フィールドをパラメータとしてクエリに渡すことにより、SQLインジェクションから保護する必要があります。

+1

これはSQLインジェクション攻撃を受けやすくなります。 –

+0

SQLの文字列のどこをハードコードするべきではありません。 Richは、これがSQLインジェクションを受けやすいということは絶対に正しいです。あなたのシステムはユーザーが誰なのかを知っているので、すべての条件チェックはデータベースセキュリティではなくアプリケーションセキュリティの一部でなければなりません。お分かりでしょうが。 –

+0

これは私の修正ではありませんが、私はこれを実装しようとしています。ありがとう –

1

テーブル内の各ユーザーをループしていますが、資格情報が一致しないユーザーが存在します。あなたのクエリ例に資格情報を追加すること

試してください:あなたは、一致を見つけた場合

command.CommandText = "select * from users where username = ?username AND password = ?password"; 
IDbDataParameter usernameParameter = _command.CreateParameter(); 
usernameParameter.ParameterName = "?username"; 
usernameParameter.Value = username; 
command.Parameters.Add(usernameParameter); 
IDbDataParameter passwordParameter = _command.CreateParameter(); 
passwordParameter .ParameterName = "?password"; 
passwordParameter .Value = password; 
command.Parameters.Add(passwordParameter); 

はその後、あなたは資格情報が正しいことを知っています。

あなたがconnection.Close()を呼び出す前に例外がスローされた場合はさておき、あなたがfinallyブロック、またはそのような使用してブロック内の接続を使用して内部のCloseコールを追加することを検討し、あなたの接続をクローズすることはできませんよう:

using (MySqlConnection connection = new MySqlConnection(MyConString)) 
{ 
    ... 
} 
0

すぐに解決策として、成功したメッセージのすぐ後に戻る必要があります。何が起こっているように見えるのは、最初に正しいユーザーアカウントに出会った後、次の反復で別のユーザーに出会ったユーザーを反復することです。正しく次にあなたのコードを置き換えることができ、問題に取り組むために

try 
{ 
    using(MySqlConnection connection = new MySqlConnection(MyConString)) 
    using(MySqlCommand command = connection.CreateCommand()) 
    { 
     command.CommandText = 
      @"SELECT CASE WHEN EXISTS (
       SELECT * from users 
       WHERE USERNAME = @Username AND Password = @Password 
       LIMIT 1) THEN 1 ELSE 0 END"; 

     try { connection.Open(); } 
     catch (Exception ex) 
     { 
      listBox4.Items.Add(ex); 
      MessageBox.Show("There has been an error connecting to the user database! Please try again later."); 
     } 

     command.Parameters.AddWithValue("@Username", textBox4.Text); 
     command.Parameters.AddWithValue("@Password", 
      CryptorEngine.Encrypt(textBox5.Text, true)); 

     Successful = (int) command.ExecuteScalar() == 1; 
     MessageBox.Show(Successful 
      ? "Successfully logged in!" 
      : "Wrong Username/Password Combination"); 
    } 
} 
catch (Exception ex) 
{ 
    listBox4.Items.Add(ex); 
} 

上記のコードは、単一の結果にクエリを制限し、あなたが潜在的なSQLを回避するために、両方のコネクタのパラメータ設定機能を使用することができます攻撃を注入し、ユーザーの身元を素早く確認します。

EDIT: EXISTS documentation

与えられたサブクエリが返す結果かどうかの回答をEXISTS、またはありません。私は、クエリを可能な限り最適化し、テーブルスキャンを避けるために使用します。 EXISTSは、サブクエリで選択リストを無視し、指定されたサブクエリに対して結果を取得できると判断できるとすぐに戻ります。 LIMITはおそらくこの例では冗長ですが、私は完全にはわかりません。この2行で

+2

クイックだが悪い解決策。データベースに100万人のユーザーがいる場合、データベースを検索して検索する前に条件付きのフィルタリングを行わなければ、ログインは終了します。 –

+0

私は完全に同意します。だから私は最新の編集でより完全なソリューションを提供しました。 –

0

:あなたが戻って、データベースからユーザーのすべてを読み、すべての戻された項目をループさ

command.CommandText = "select * from users"; 

while (Reader.Read()) 
{ 

} 

。その後、持っている:

if (textBox4.Text == Reader.GetString(2)) 
{ 
    .... 
} 
else 
{ 
    MessageBox.Show("Wrong Username/Password Combination"); 
} 

このコードを使用すると、あなたが入力ボックスに入力されたものではないのですすべてのユーザーのために、「間違ったユーザー名/パスワード」というメッセージをプリントアウトします。

あなたはどちらかだけのフォームに入力された特定のユーザを探すことができます:あなたは、これは、より良い構築できますが

bool loggedIn = false; 
while (Reader.Read()) 
{ 
    if (textBox4.Text == Reader.GetString(2)) 
    { 
     string haspass= CryptorEngine.Encrypt(textBox5.Text, true); 
     if (haspass == Reader.GetString(3)) 
     { 
      loggedIn = true; 
     } 
    } 
} 

if (loggedIn) 
{ 
    MessageBox.Show("Successfully logged in!"); 
} 
else 
{ 
    MessageBox.Show("Wrong Unhashed Username/Password Combination"); 
} 

command.CommandText = "select * from users where username = @username"; 
command.Parameters.AddWithValue("@username", textBox4.Text); 

か1つだけエラーメッセージを印刷します。

実際にユーザー名とパスワードの両方を送信すると、一度にチェックを行うことができます。その名前のユーザーがいないか、パスワードが間違っていれば、結果は返されませんが、組み合わせが正しい場合は、結果が1つだけになり、ユーザーはこれ以上実行することなく有効であることがわかりますチェック。

0

あなたが持っているコード:command.CommandText = "select * from users"あなたはログインしようとしているデータベース内の各ユーザーのためです。あなたには2人のユーザーがおり、あなたのログインデータはその1人でOKです。成功した直後に機能から復帰し、ユーザーが誰も成功しなかった場合にのみ失敗しました。

0

すべてのユーザーにループします。資格情報が最初のものと一致し、「ログイン」して次のログインに失敗することがあります。

1

あなたはすべてのユーザーを照会し、それらのすべてをテストし、それぞれにメッセージを送ります。可能であれば、オリジナルのselectをユーザ名のwhereに制限する必要があります。

理想的なシナリオでは、ユーザーレコードに「塩」を付け、ハッシュでそれを使用します(レインボーテーブルやその他のユーザー固有の方法による破損を防ぐため)。これは私だった場合、私は(簡潔にするため、「Dapperの」構文を使用して)のようなものを持っているでしょう。ここ

string name = ... // whichever text.Text 
string pw = ... 
var row = connection.Query("select Salt, Hash from Users where Username = @name", 
      new {name}).SingleOrDefault(); 
bool loggedIn = false; 
if(row != null) 
{ 
    byte[] salt = row.Salt, hash = row.Hash; 
    loggedIn = BlobsAreEqual(CryptorEngine.Encrypt(pw, salt, true), hash); 
} 
// maybe add random wait here, to slow down brute-force 
if(loggedIn) { 
    // great! 
} else { 
    // increment failed counter, and potentially lock out account 
} 
関連する問題