Защита веб-приложений работающих с базой данных (начало)

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

Многие Web-приложения хранят свои постоянные данные в базах данных (БД). Сегодня таких приложений уже стало так много, что невозможно рассмотреть каждое из них. Поэту в этой статье я рассматриваю возможность взлома и защиты приложений, работающих с БД. Ключевой момент этой статьи – доверие введённым данным и опасность атак с внедрением SQL-кода. Многие просто и не догадываются, что их базы данных уязвимы для атак, заключающихся в манипуляции со структурой запросов.

Многие приложения, созданные как начинающими программистами, так и более опытными, содержат примерно такой код:

string sql = “select * from clients where name = ‘”+name+”‘ and age=”+age

Тут обычно значение переменных name и pass запрашивается у пользователя, это может быть запрос через форму, через службу авторизации, через обычную передачу запросами POST или GET.

Допустим, пользователь вводит свои данные имя – Ivan, возраст – 21, тогда этот запрос будет иметь такой вид:

select * from clients where name = ‘Ivan’ and age=21.

Такой SQL-запрос, конечно, выведет информацию о пользователе Ivan (конечно, если такой существует и указан правильный пароль).

А что если наш пользователь «плохой парень», и введёт в качестве своего имени следующее: Ivan’ or 1=1 — ?

Тут, наверное, будет ошибка или будет пользователь не найден? Да уж, нет. На самом деле этот запрос вернёт всё содержимое таблицы clients. Почему? Да очень просто, обратите внимание на «– » в конце имени пользователя. Это оператор комментария, который поддерживает большинство современных СУБД: Microsoft SQL Server, IBM DB2, Oracle, PostageSQL, MySQL. Поэтому наш запрос по сути будет иметь такой вид:

select * from clients where name = ‘Ivan’ or 1=1.

Данная атака называется внедрением SQL-кода. (SQL injection). В подобной ситуации изменяется логика SQL-выражения за счёт включения оператора “or”.

По умолчанию многие СУБД разрешают за один запрос выполнять более одного SQL-выражения. Например, разрешается отправить на SQL-сервер такой запрос:

select * from clients select * from managers и будут выполнены оба оператора select.

При взломе очень легко воспользоваться этой возможностью. Допустим, в наш запрос хакер в качестве имени вводит: Ivan drop table clients -.

В результате SQL-запрос сначала вернёт все записи с полем name равным Ivan, а потом удалит всю таблицу клиентов :-).

Отсюда можно сделать выводы:

  • никогда не создавайте подключения к базе данных СС импользованием учётных записей sa (Microsoft SQL Server), internal (Oracle), root (MySQL), потому что они обладают максимальными полномочиями и способны нанести непоправимый ущерб.
  • никогда не выводите обычному пользователю сообщение об ошибке SQL-сервера. Обычно такие сообщения содержат SQL-код, в котором произошла ошибка, и выведя SQL-запрос, мы только окажем хакеру неоценимую услугу.

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

string name=”Ivan’ or 1=1 int age=21;

name=name.Replace(“‘”,”””);

string sql = “select * from clients where name = ‘”+name+”‘ and age=”+age Таким образом лишают хакеров возможности провести атаку, поскольку до оператора комментария образуется некорректное выражение: select * from clients where name = ‘Ivan” or1=1’ and age=21. Но это не спугнёт хакера – для атаки он воспользуется числовым полем age.

Например, в качестве возраста он введёт 35; shutdown, и наш сервер остановится.

Если всё равно верить, что кавычки спасают, то хакер может воспользоваться функцией char(0x27), которая позволяет их скрыть.

Ещё один распространённый метод избавиться от такой ошибки – это использовать хранимые процедуры. Но он тоже не правилен! Он предотвратит лишь некоторые атаки!

Допустим, у нас есть хранимая процедура sp_GetName, и вот код, вызывающий её:

string name = //Имя, введённое пользователем

SqlConnection sql=new SqlConnection(ConnectionString);

sql.Open();

string sqlstring=”exec sp_GetName ‘”+name+”;”;

SqlCommand = new SqlCommand(sqlstring, sql);

Попытка ввести «Ivan’ or 1=1 – » закончится неудачей, поскольку нельзя выполнить соединение (join) между вызовами хранимых процедур. Такой вызов некорректен:

exec sp_GetName ‘Ivan’ or 1=1 -‘

Однако такое манипулирование абсолютно не приводит к ошибке: exec sp_GetName ‘Ivan’ insert into clients(name) values(‘Tanya’) -‘ Эта SQL-команда получит данные о клиенте с именем Ivan и вставит новую запись клиента с именем Tanya.

Как видно, хранимые процедуры не спасают от обсуждаемой ошибки!

Какие же средства использовать для предотвращения взлома нашей СУДБ?

Построение выражений программным путём довольно проблематичный способ. Самый простой способ избежать проблем – переложить построение SQL-выражений на базу данных и не пытаться конструировать их в коде приложения. Следует использовать символы подстановки (place holder), которые часто называют параметризированными командами (parameterized command). При написании запроса вы сами определяете, какие части SQL-выражения должны быть параметрами. Вот параметризированная версия SQL-запроса:

select * from client where name=? And age=?

Затем следует присвоить конкретные значения параметрам, которые передаются в БД вместе с SQL-запросом.

 

string strName=… ;

int strAge=… ;

SqlConnection conn=new SqlConnection(ConnectionString);

conn.Open();

SqlCommand cmd = new SqlCommand();

cmd.CommandText=”select * from clients where name=? and age=?”;

SqlParameter par=cmd.CreateParameter();

par.ParameterName=”name”;

par.Value=strName;

cmd.Parameters.Add(par);

par=cmd.CreateParameter();

par.ParameterName=”age”;

par.Value=strAge;

par.SqlDbType=SqlDbType.Int;

cmd.Parameters.Add(par);

SqlDataReader rd=cmd.ExecuteReader();

 

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

Добавить комментарий

Ваш адрес email не будет опубликован.

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.