Используя oledb для подключения к СУБД MS Access 2007 с файлом


Я работаю на программу, которая использовать oledb для подключения к файл MS Access 2007 для. Моя программа имеет возможность добавления и удаления записей из файла с помощью SQL-запросов, выберите удалить элемент по ID.

Так вот, меня предупредили, что мой код может привести к SQL-инъекции, которая будет удалять все записи из файла. Как я могу предотвратить это? Где кроется проблема? Один человек отметил, что я мог бы избежать, имея хорошие проверки на месте, но то, что я должен проверить?

Это, как я удалить элементы:

// SQL query which will delete entry by using entry ID.
string SQL = "DELETE FROM PersonalData WHERE DataID = " + txtEntryID.Text;

private void DeleteData(string SQL)
{
    // Creating an object allowing me connecting to the database.
    // Using parameters in command will avoid attempts of SQL injection.
    OleDbConnection objOleDbConnection = new OleDbConnection();
    // Creating command object.
    objOleDbConnection.ConnectionString =
        "Provider=Microsoft.ACE.OLEDB.12.0;" +
        "Data Source=" + filePath + ";" +
        "Persist Security Info=False;" +
        "Jet OLEDB:Database Password=" + pass + ";";
    OleDbCommand objOleDbCommand = new OleDbCommand();

    objOleDbCommand.CommandText = SQL;

    // Assigning a connection string to the command.
    objOleDbCommand.Connection = objOleDbConnection;

    try
    {
        // Open database connection.
        objOleDbConnection.Open();
        objOleDbCommand.ExecuteNonQuery();
    }
    catch (Exception ex)
    {
        // Displaying any errors that 
        // might have occured.
        MessageBox.Show("Error: " + ex.Message);
    }
    finally
    {
        // Close the database connection.
        objOleDbConnection.Close();
    }

    // Refreshing state of main window.
    mainWindow.DisplayFileContent(filePath);

    lblMessage.Text = "Data was successfully deleted.";

    // Clearing text box field.
    txtEntryID.Clear();
}


2377
5
задан 1 декабря 2011 в 07:12 Источник Поделиться
Комментарии
6 ответов

Если я не ошибаюсь, вы используете нефильтрованное пользователя от txtEntryID.
Никогда не доверяйте ввод данных пользователем.

Что делать, если пользователь заполняет txtEntryID с 123 или 1=1?
Запрос будет удалить все:

DELETE FROM PersonalData WHERE DataID = 123 OR 1=1

Что, если, затем, пользователь вводит 123; обновление учетной записи кредит = 1000 где userId = мне:

DELETE FROM PersonalData WHERE DataID = 123; UPDATE Account SET credit = 1000 WHERE userId = me

8
ответ дан 1 декабря 2011 в 09:12 Источник Поделиться

Посмотрите на ANeves описание SQL-инъекций.

Я просто покажу решение проблемы:

Сначала измените запрос, включающий заполнитель параметр, такой:

string query = "DELETE FROM PersonalData WHERE DataID = ?";

Позже, когда вы строите ваш запрос, необходимо добавить параметр для объекта oledbcommand:

var cmd = new OleDbCommand(query);
cmd.Parameters.Add(new OleDbParameter{Value = txtEntryID.Text};

... и тогда вы будете готовы, чтобы выполнить запрос, как и раньше.

Механизм параметров ADO.NET заботится о всех известных побегов, которые необходимы для предотвращения SQL-инъекции атаки, если вы создаете вы запросы правильно.

6
ответ дан 1 декабря 2011 в 01:12 Источник Поделиться

Ваш код может быть легко использована, как ANeves показал.

В вашем случае небольшое исправление может сделать его безопасным. Просто парсинг ID, как целое, он полностью безопасен. Целое число не может содержать каких-либо вредных код:

int id = Int32.Parse(txtEntryID.Text);
string SQL = "DELETE FROM PersonalData WHERE DataID = " + id.ToString();

Добавления значения в SQL-кода, однако, как правило, считается плохой практикой. Общее решение для обработки пользовательского ввода в запросах безопасным способом является использование параметризованными запросами, как Einbu Арьян описано.

Все-таки разбора,.


Я сделал некоторые предложения изменить ваш метод базы данных, что делает его многоразовым:

// Take a parameter that is a delegate for code that sets parameters
private static void ExecuteSql(string sql, Action<OleDbCommand> setParameters) {

// Use 'using' to make sure that the objects are disposed correctly
// No 'obj' prefix on variables, hungarian notation is not needed for type
// No 'OleDb' in the variable name, that information is not needed in the name
using (OleDbConnection connection = new OleDbConnection()) {

objOleDbConnection.ConnectionString =
"Provider=Microsoft.ACE.OLEDB.12.0;" +
"Data Source=" + filePath + ";" +
"Persist Security Info=False;" +
"Jet OLEDB:Database Password=" + pass + ";";

// Set query and connection in the command constructor
using (OleDbCommand command = new OleDbCommand(sql, connection)) {

// Call code that sets the parameters
if (setParameters != null) {
setParameters(objOleDbCommand);
}

try {
connection.Open();
command.ExecuteNonQuery();
} catch (Exception ex) {
MessageBox.Show("Error: " + ex.Message);
}
// No 'finally' block, as the 'using' block closes the connection

}
}
}

// Overload for no parameters
private static void ExecuteSql(string sql) {
ExecuteSql(sql, null);
}

Использование:

// Parse the input
int id = Int32.Parse(txtEntryID.Text);
// Call the method with a lambda expression for setting parameters
// Set the parameter with type and value
ExecuteSql(
"DELETE FROM PersonalData WHERE DataID = ?",
command => {
command.Parameters.Add("?", OleDbType.Integer).Value = id;
}
);
// Handle UI stuff
mainWindow.DisplayFileContent(filePath);
lblMessage.Text = "Data was successfully deleted.";
txtEntryID.Clear();

4
ответ дан 1 декабря 2011 в 04:12 Источник Поделиться

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

using(var cn = new OleDbConnection(connectionString))
{
// open your connection here if needed
// run your querie(s) here
} //cn.Dispose() is call here automatically, and that will also close the connection

Это позволит улучшить читаемость и понятность кода, поместив соответствующий код вместе, а также сократить строки кода.

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

2
ответ дан 1 декабря 2011 в 01:12 Источник Поделиться

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

Как:

var cn = new OleDbConnection(connectionString);

// instead of:
var cn = new OleDbConnection();
cn.ConnectionString = connectionString;

и

var cmd = new OleDbCommand(query);

// instead of:
var cmd = new OleDbCommand();
cn.CommandText = query;

2
ответ дан 1 декабря 2011 в 01:12 Источник Поделиться

Другим решением было бы правильно фильтровать ввод. Это легче, и это еще более опасно, потому что легко что-то упустить.

Для примера под рукой, нужно разобрать ввод пользователей в число, а затем преобразовать это число обратно в строку, чтобы добавить его в свой SQL-строку, следующим образом:

int dataid = int.Parse( txtEntryID.Text ); //will throw exception if not valid number
string SQL = "DELETE FROM PersonalData WHERE DataID = " + dataid; //implies dataid.ToString();

В случае строковых параметров задача еще больше усложняется, потому что вы должны убедиться, что строка не содержит никаких символов ниже \u0020, что любые одинарные кавычки внутри строки правильно уходил от ы = ы.Заменить("'", """), и что любые другие символы, которые могут иметь особое значение в рамках СУБД вы используете несколько ободрана.

2
ответ дан 1 декабря 2011 в 02:12 Источник Поделиться