Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Защита кода работы с БД


Visual Basic: новости сайтов, советы, примеры кодов

VBNet.Ru
Выпуск от Павла Сурменка



А мы вас ищем!

Проект Web Reflection объявляет конкурс на несколько должностей.

Первая категория: разработчики ASP .NET, имеющие опыт разработки более-менее серьезных приложений.  Работа удаленная, т.е. вы можете находиться где угодно, в любом городе и любой стране. Оплата сдельная (оплачивается полностью разработка проекта). Проекты, которые мы разрабатываем – в основном системы по автоматизации бизнеса, а также решения в области электронной коммерции.

Требований к образованию, официальному трудовому стажу и т.п. нет. Необходим опыт разработки на ASP .NET (на C# или VB), SQL Server. Не помешают знания в области проектирования архитектуры ПО.

Вторая категория: разработчики ASP .NET, возможно с малым опытом разработки, но желанием учиться. Сейчас у нас в разработке большой проект (типовое решение мультиязычного информационного  портала с более 20-ти разделов), вы сможете получить реальный опыт работы в команде и разработки крупных сайтов. Работа в процессе разработки оплачиваться не будет, но вы сможете повысить свою квалификацию, работая бок-о-бок с нашими специалистами, а также получить вознаграждение после окончания проекта.

По всем вопросам пишите на cdm@webreflection.ru или на ICQ: 326066673 . Для профессиональных разработчиков желательно указать в письме список ранее реализованных на ASP .NET проектов, а также примерную стоимость вашего труда в расчете на час работы и сколько вы можете времени в неделю выделять на работу с нами. Для тех, кто заинтересовался разработкой портала, также неплохо указать информацию о выполненных проектах, чтобы я мог иметь представление о вашей квалификации, и сколько вы времени в неделю можете выделять на разработку.

Защита БД

Создавая приложения, работающие с базами данных, ни в коем случае нельзя забывать о безопасности. Дыры, оставленные в безопасности кода, работающего с БД, могут дорого стоить. Представьте, что будет, если злоумышленник оформит в интернет-магазине заказ, не заплатив ни копейки? Или удалит документы из системы электронного документооборота фирмы? Вероятность взлома можно существенно снизить, если при разработке ПО учитывать требования к безопасности, и помнить несколько нехитрых правил.

Ниже цитата с форума dev.net.ua, автор Артем Кривокрисенко:


На мой взгляд самый распространенный и самый опасный способ взлома базы данных - это SQL Injection - внедрение в обычные SQL-запросы, с которыми регулярно работает приложение, своих вредоносных запросов. Эта проблема происходит как правило когда данные, полученые от пользователя бездумно помещают в SQL запрос методом конкатенации (пример близкий по тексту тому что демонстрировал Сергей Байдачный на Dev Days):

Dim CommandText As String = "SELECT COUNT(*) FROM Users WHERE UserName='" + UserName.Text + "' AND Password='" + Password.Text + "'"
Dim Command As New SqlCommand(CommandText, Connection)

If CInt(Command.ExecuteScalar) = 1 Then
' Логин и пароль верны
Else
' Неверный логин или парль
End If

Очевидно что при вводе логина и пароля Brand/123 мы в результате конкатенации получим следующий запрос:

SELECT COUNT(*) FROM Users WHERE UserName='Brand' AND Password='123'

Тем не менее ввести в текстовые поля мы можем и другие данные, например в поле логина ввести Viktor' --, а в поле пароля к примеру тот же 123. Таким образом в БД у нас отправится запрос:

SELECT COUNT(*) FROM Users WHERE UserName='Viktor' --' AND Password='123'

Поскольку SQL Server считает все что идет после символов "--" коментарием, то мы фактически получаем возможность выполнить вход в систему от имени другого пользователя не зная его пароль.

Таким же методом можно отправить в БД 2 запроса, разделенных символом ";":

SELECT COUNT(*) FROM Users WHERE UserName='Viktor'; DROP TABLE Users --' AND Password='123'

Результат предсказуем - вся наша база пользователей будет уничтожена.

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

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

Dim CommandText As String = "SELECT COUNT(*) FROM Users WHERE UserName = @UserName AND Password = Password"
Dim Command As New SqlCommand(CommandText, Connection)
Command.Parameters.Add("@UserName", SqlDbType.NVarChar, 256).Value = UserName.Text
Command.Parameters.Add("@Password", SqlDbType.NVarChar, 256).Value = Password.Text

If CInt(Command.ExecuteScalar) = 1 Then
' Логин и пароль верны
Else
' Неверный логин или парль
End If

Во-первых, в этот запрос уже в принципе невозможно пробиться через SQL Injection, во-вторых, такие запросы будут выполняться быстрее (я, правда, не уверен что разница будет сколько-нибудь ощутимой, но все равно приятно). Также это упрощает работу с рядом типом данных, которые методом конкатенации не совсем просто отправить в БД (даты, бинарные данные, GUID'ы) - в случае же параметризированых запросов все очень просто - у каждого параметра указывается тип и значение, остальное берут на себя классы SqlClient и SQL Server.

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

Как видите, защититься от SQL-инъекций совсем несложно, у "правильных" разрабочтиков эта защита есть по умолчанию. Тем не менее интернет просто кишит сайтами с SQLI-дырками :)

 

На самом деле данный пример имеет еще одну проблему, о которой Сергей (наверняка из-за отсутствия времени) не упомянул - в нашей таблице пароль - эта строка, а SQL Server сравнивает строки без учета регистра, поэтому мы сможем зайти в базу с паролем "hello world", "Hello WORLD" и "HeLlO WoRlD" - для проверки я выполняю приведение данных к бинарному типу (этот метод я подсмотрел в одной из статей MSDN):

SELECT COUNT(*) FROM Users WHERE UserName = @UserName AND CONVERT(varbinary, Password)=CONVERT(varbinary, @Password)

Еще более правильно - хранить пароль в зашифрованом виде или только хэш пароля (оба эти метода, наряду с хранением пароля в открытом виде поддерживаются в инфраструктуре Membership ASP .NET 2.0) - даже если кто-то пробьется в базу данных, ничего интересного он там не найдет.

 

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

Например, если у сервера баз данных, или даже у одной базы данных много пользователей, то рано или поздно возникает необходимость ограничить некоторые данные от любопытных глаз. К примеру списки партнеров/клиентов, истории финансовых операций и т.п. - в этом случае необходимо распределение уровней доступа к различным объектам для различных пользователей. Классически рекомендуется выдавать пользователям минимум привелегий, разделять доступ на уровнях баз данных и таблиц.

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

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

 

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

К примеру у меня на сервере уже месяцев 6 круглосуточно с разных IP ломятся по логинам sa, admin и root (???), увы логин sa заблокирован, а admin и root вообще не существуют!

 

Также хотелось обратить внимание еще на одну уязвимость - она не имеет прямого отношения к безопасности самого сервера баз данных, тем не менее предоставляет для него большую угрозу. Эта проблема в большей степени относится к так называемым shared-хостингам, когда на одной Windwos-машине держат несколько сотен сайтов.

Как организовывается их хранение и работа?

В каталоге, скажем, d:\Home\ для каждого сайта создается отдельная директория, в IIS для него создается веб-узел, ссылающийся на эту директорию, для узла указывают host headers, соответствующий доменам этого сайта. FTP-доступ организовывается не встроеным в IIS FTP-сервером, а каким-то сторонним, в учетной системе этого FTP-сервера для каждого клиента заводится логин/парль и он ассоциируется с соответствующей директорией в d:\Home\. Разумеется каждый пользователь может обратиться только к своей директории, в чужие его FTP не пустит.

Но теперь посмотрим что происходит в IIS - все веб-сайты настроены на запуск в контексте NETWORK SERVICE. Это удобно по той причине, что все веб-сайты можно будет запустить в одном (или нескольких) пулах, и для этого потребуется меньше ресурсов чем на запуск каждого веб-сайта в контексте отдельного Windows-акаунта и соответственно отдельного пула.

Но поскольку все сайты выполняются под NETWORK SERVICE, то для этого акаунта открыт полный доступ ко всей директории d:\Home\ (иногда как на чтение, так и на запись!). Но поскольку код моего веб-сайта выполняется под NETWORK SERVICE, а NETWORK SERVICE имеет неограниченый доступ к директории d:\Home\, то я могу обратиться к файловой системе и фактически получить неограниченый доступ к содержимому всей директории - включая директории всех сайтов, которые находятся на этом сервере. Таким образом я могу без проблем получить на руки исходные коды, какие-то документы, не предназначеные для чужих глах, разумеется, к конфигурационным файлам, в которых у нас хранятся логин и пароль от базы данных , причем как правило логин - это db_owner, также может храниться логин/пароль от SMTP. Не исключе кстати, что NETWORK SERVICE сможет безпрепятственно пройти на системный диск, и даже записать/перезаписать/удалить на нем что-нибудь. Последствия от таких "путешествий" по файловой системе могут быть катастрофическими для клиентов хостинг-провайдера и для самого хостинг-провайдера.

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

Также я видел советы шифровать пароли в web.config, но если честно я не уверен что это может как-то помочь - в любом случае где-то нужно хранить ключ которым эти данные расшифровываются - его злоумышленник сможет легко достать аналогичным образом.

 

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


 

Спасибо Артему за подробный рассказ. Могу внести лишь одно дополнение. Артем говорит, что «Таким же методом можно отправить в БД 2 запроса, разделенных символом ";"». Так вот, прочитав это вы можете решить, что нужно фильтровать в запросе символ “;”, и тогда всё будет в порядке. Ничего подобного! Символ “;” не является обязательным, и если его убрать, то все равно оба запроса (свой и вражеский) будут выполнены.

Вообще иногда можно видеть как для защиты от SQLI предлагают фильтровать некоторые ключевые слова в запросе (тот же DROP, TRUNCATE, DELETE и др.). Это может немного помочь, но лишь немного. И, с другой стороны, может посчитать вредоносным и самый безобидный запрос. Такие меры не смогут обеспечить 100-процентную защиту.

И еще один момент. Можно предположить, что с помощью SQLI злоумышленник сможет навредить только базе данных. Если вы тоже так считаете, то вы плохо знакомы с SQL Server. Это достаточно мощная система, и она может многое, в т.ч.с помощью T-SQL можно получить доступ к файловой системе. И, насколько я помню, даже можно выключить сервер. Если конечно у пользователя, в контексте которого выполняет запросы злоумышленник, есть права на это.

Ну и в завершение рекомендую приобрести и прочесть книгу «Защищенный код». Замечательная книга, одна из немногих, которые всегда лежат у меня на столе (наряду с «Архитектурой корпоративных программных приложений» Мартина Фаулера и некоторых других). Must read для всех разработчиков без исключения!

 

Павел Сурменок

VBNet

Web Reflection


В избранное