C # - несколько, если еще оператор не работает правильно - PullRequest
1 голос
/ 05 декабря 2011

Я использую .net разъем для MySQL. Я пошел, чтобы закодировать форму входа пользователя, которая, кажется, работает правильно, но когда я нажимаю кнопку входа в систему с действительными данными для входа, он говорит мне, что я вошел в систему, а затем говорит мне, что это неправильная комбинация user / pass.

вот код, и все выглядит так, как должно быть.

Программа сверяет хешированный пароль с паролем, введенным в базу данных, и все работает хорошо. Но по какой-то причине появляется сообщение «успешно зарегистрирован», а затем сразу появляется сообщение «неправильное имя пользователя / пароль».

Я пытался выяснить, где я ошибся последние 2 дня, и это сводит меня с ума. может быть, вы, ребята, можете увидеть, где я облажался LOL

код:

            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);
        }

Ответы [ 8 ]

4 голосов
/ 05 декабря 2011

Выглядит так, как будто ваш DataReader возвращает более одного результата, код попадает в успешный путь для первого результата, а затем в неудачный путь для второго результата.

Вам нужно сделать свой SQLболее конкретно, вместо того, чтобы запрашивать у всех пользователей select * from users, вам нужно только запрашивать информацию о пользователе, который пытается войти в систему, что-то вроде (псевдокод) -

select * from users where username = yourusernamefield

Где значение yourusernamefield было взято из вашей формы.Вам нужно будет защитить от внедрения SQL, передавая поле имени пользователя в качестве параметра для вашего запроса.

3 голосов
/ 05 декабря 2011

Вот лучший способ сделать это:

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);
}

Это вернет только одну строку (если она существует).

1 голос
/ 05 декабря 2011

Вы запрашиваете у всех пользователей, тестируете их всех и отправляете сообщения каждому из них. Если возможно, вы должны ограничить исходное значение select с помощью where в имени пользователя.

В качестве наблюдения, в идеальном сценарии вы должны иметь «соль» в записи пользователя и использовать ее в хэше (чтобы предотвратить взлом через радужную таблицу или другие не связанные с пользователем методы). Например, если бы это был я, у меня было бы что-то вроде (используя краткий синтаксис для краткости):

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
}
1 голос
/ 05 декабря 2011

Вы просматриваете каждого пользователя в таблице, конечно, будет пользователь, чьи учетные данные не совпадают.

Попробуйте добавить учетные данные в свой запрос, например:

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() выдается исключение, рассмотрите возможность добавления Close вызов внутри блока finally или использование вашего соединения в блоке using следующим образом:

using (MySqlConnection connection = new MySqlConnection(MyConString))
{
  ...
}
0 голосов
/ 05 декабря 2011

Вы перебираете всех пользователей.Учетные данные совпадают для первого, и вы можете «войти», а следующий не получится.

0 голосов
/ 05 декабря 2011

В коде у вас есть: command.CommandText = "select * from users", поэтому для каждого пользователя в базе данных вы пытаетесь войти. Вероятно, есть 2 пользователя, и ваши логин данные в порядке для одного из них. Вы должны вернуться из функции сразу после успеха, а показ не удался, только если ни один из пользователей не преуспел.

0 голосов
/ 05 декабря 2011

С этими двумя строками:

command.CommandText = "select * from users";

while (Reader.Read())
{

}

Вы читаете всех пользователей обратно из базы данных и перебираете все возвращенные элементы.После этого вы получите:

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

С этим кодом вы распечатаете сообщение «Неверное имя пользователя / пароль» для каждого пользователя, который не введен в поле ввода.

Вы можетелибо просто найдите конкретного пользователя, введенного в форму:

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

, либо просто напечатайте одно сообщение об ошибке:

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");
}

Хотя вы могли бы структурировать это лучше.

На самом деле, если вы отправите имя пользователя и пароль вниз, вы можете выполнить проверку за один раз.Если пользователь с таким именем отсутствует или пароль неправильный, результаты не будут возвращены, но если комбинация верна, то будет ровно один результат, и вы будете знать, что пользователь действителен без каких-либо дальнейших действий.проверка.

0 голосов
/ 05 декабря 2011

Как немедленное решение, вы должны вернуться сразу после вашего успешного сообщения. Кажется, что происходит то, что вы перебираете пользователей, сталкиваясь сначала с правильной учетной записью пользователя, а затем на следующей итерации с другим пользователем.

Чтобы правильно решить проблему, вы можете заменить код следующим:

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 отвечает, возвращает ли данный подзапрос результаты или нет. Я использую его, чтобы убедиться, что запрос максимально оптимизирован, и чтобы избежать сканирования таблицы. EXISTS будет игнорировать список выбора в подзапросах и вернется, как только сможет определить, что для данного подзапроса могут быть получены любые результаты. LIMIT, вероятно, избыточен в этом примере, но я не совсем уверен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...