.NET / C # проверка, если запрос SQL изменяет базу данных, и если не выполняется - PullRequest
2 голосов
/ 22 августа 2011

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

Проблема в том, что я хочу запретить всезапросы, которые изменяют базу данных любым способом.Мне не удалось найти способ сделать это, и я приложил все усилия с Google.

Решение, которое я могу придумать, состоит в том, что я буду сканировать запрос на INSERT, DELETE, UPDATE и разрешать только операторы SELECT.Однако я хочу, чтобы пользователи могли также вызывать хранимые процедуры.Это означает, что мне нужно получить тело хранимой процедуры и отсканировать ее перед выполнением.Как мне тогда загрузить хранимую процедуру?

Если кто-нибудь знает способ выполнения запросов только для чтения, поделитесь, пожалуйста!У меня такое чувство, что сканирование текста на наличие INSERT, DELETE, UPDATE не предотвращает инъекции SQL.

Ответы [ 9 ]

12 голосов
/ 22 августа 2011

Самый простой способ сделать это - выгрузить это задание в базу данных.Просто убедитесь, что пользователь базы данных, который будет выполнять запросы, имеет доступ на чтение только .Тогда любые запросы, которые делают что-либо кроме SELECT, будут терпеть неудачу, и вы можете сообщить об этой ошибке пользователям.

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

Даже в этом случае убедитесь, что вы нене пропускайте конфиденциальные данные через ваши запросы.Непосредственный ввод запросов от пользователей сайта может быть опасным, если вы не будете осторожны.Даже если вы разрешаете эти запросы для чего угодно, кроме специально созданной базы данных песочницы, это «упс, я случайно изменил разрешения пользователя», чтобы не превращаться в кошмар безопасности.

Другой вариант - написать «создатель запроса»."страница, где пользователи могут выбрать таблицу и столбцы, которые они хотели бы видеть.Затем вы можете а) отображать только те таблицы и столбцы, которые подходят для данного пользователя (возможно, на основе пользовательских ролей и т. Д.) И б) самостоятельно генерировать SQL, предпочтительно с помощью параметризованного запроса.

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

4 голосов
/ 22 августа 2011

Как насчет создания учетной записи пользователя на сервере базы данных, который имеет только права выбора (только для чтения)?

2 голосов
/ 22 августа 2011

Возможно, вы могли бы настроить пользователя SQL с доступом только для чтения к базе данных и выполнить команду, используя этого пользователя? Тогда вы можете отследить ошибки, когда / если они произойдут.

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

1 голос
/ 22 августа 2011

Лучше всего не разрешать пользователям вводить SQL и использовать только подготовленные / параметризованные запросы ...

Следующий лучший способ предотвратить это - использовать пользователя с ограниченным доступом с чистым доступом для чтения.Вышеупомянутые два могут быть объединены ...

ВНИМАНИЕ Чтобы выполнить хранимую процедуру, пользователь должен иметь привилегию выполнения ... Если хранимая процедура изменяет данные, то это произойдет без сообщений об ошибках даже с ограниченным пользователем, поскольку разрешение на изменение предоставляется хранимой процедуре!

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

Что касается того, как загрузитьтело хранимой процедуры - это зависит от используемой вами БД (SQL Server, Oracle и т. д.).

РЕДАКТИРОВАТЬ:

Другим вариантом является так называемый «Брандмауэр базы данных» - вы подключаетесь, а не напрямую к БД, к Брандмауэру ... В Брандмауэре вы настраиваете несколько вещей, например ограничения по времени (когда конкретные пользователи / операторы/ art не допускается), оператор на основе SQL (который разрешен ...), ограничения на основе количества (например, вы можете получить 100 записей, но не можете загрузить всю таблицу / БД ...) и т. д.Существуют коммерческие и открытые брандмауэры БД с открытым исходным кодом, хотя они по своей природе очень зависят от используемой БД и т. Д.

Примеры:

  • Oracle Firewall - работает с Oracle / SQL Server / DB2 и т. Д.
  • SecureSphere - несколько, включая Oracle / SQL Server / DB2и т.д.
  • GreenSQL - поддержка версий с открытым исходным кодом Postgres + MySQL, коммерческий MS SQL Server
1 голос
/ 22 августа 2011

Вы не можете надежно разобрать SQL.

Использовать разрешения для

  1. Разрешить только SELECT для таблиц и представлений
  2. Нет разрешений для хранимых процедур, которые изменяют данные (Конечный пользователь по умолчанию не сможетчтобы увидеть определение хранимой процедуры)
0 голосов
/ 17 января 2017

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

public static bool ValidateQuery(string query)
{
    return !ValidateRegex("delete", query) && !ValidateRegex("exec", query) && !ValidateRegex("insert", query) && !ValidateRegex("alter", query) &&
           !ValidateRegex("create", query) && !ValidateRegex("drop", query) && !ValidateRegex("truncate", query);
}
public static bool ValidateRegex(string term, string query)
{
    // this regex finds all keywords {0} that are not leading or trailing by alphanumeric 
    return new Regex(string.Format("([^0-9a-z]{0}[^0-9a-z])|(^{0}[^0-9a-z])", term), RegexOptions.IgnoreCase).IsMatch(query);
}

Вы можете увидеть, как это работает здесь: регулярное выражение
см. регулярные выражения: cheatsheet1 , cheatsheet2

обратите внимание, что это не идеально, поскольку он может блокировать запрос с одним из ключевых слов в качестве кавычки, но если вы напишете запросы и это просто предосторожность, то это может помочь.

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

public static bool IsDbAffected(string query, string conn, List<SqlParameter> parameters = null)
{
    var response = false;
    using (var sqlConnection = new SqlConnection(conn))
    {
        sqlConnection.Open();
        using (var transaction = sqlConnection.BeginTransaction("Test Transaction"))
        using (var command = new SqlCommand(query, sqlConnection, transaction))
        {
            command.Connection = sqlConnection;
            command.CommandType = CommandType.Text;
            command.CommandText = query;
            if (parameters != null)
                command.Parameters.AddRange(parameters.ToArray());
            // ExecuteNonQuery() does not return data at all: only the number of rows affected by an insert, update, or delete.
            if (command.ExecuteNonQuery() > 0)
            {
                transaction.Rollback("Test Transaction");
                response = true;
            }
            transaction.Dispose();
            command.Dispose();
        }
    }
    return response;
}

Вы также можете объединить их.

0 голосов
/ 22 августа 2011

Ваш первый шаг должен состоять в том, чтобы создать пользователя БД для этой конкретной задачи только с необходимыми разрешениями (в основном только SELECT) и с правами на просмотр только тех таблиц, которые вам нужны, чтобы они могли (чтобы они не могли выбирать таблицы sys иливаша таблица пользователей).

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

Может быть, на каком бы языке вы ни программировали пользовательский интерфейс, вы можете попытаться посмотретьонлайн для пользовательского элемента управления, который позволяет фильтровать базу данных. Google it ...

0 голосов
/ 22 августа 2011

я думаю SQL Trigger - лучший способ, которым вы хотите заниматься.

0 голосов
/ 22 августа 2011

Не забывайте о вещах, которые даже хуже, чем INSERT, UPDATE и DELETE. Как TRUNCATE ... это плохие вещи.

...