понедельник, 14 января 2013 г.

MSSQL : Практика предотвращения SQL-injection

Безопасность данных – не место для халтуры

Атака вида SQL-injection продолжает оставаться одной из самых серьезных угроз для SQL Server. База данных может быть восприимчива к таким атакам, если она или приложение (в основном это веб-приложения) содержат код, который хакер может использовать для ввода дополнительной команды SQL в одном из полей ввода приложения. Затем приложение подставляет модифицированный код в базу данных, в результате хакер может получить доступ к конфиденциальной информации, изменению данных или объектов базы данных, и запуску административных операций в базе данных или, в некоторых случаях, по отношению к операционной системе.

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

Введение в SQL-injection

Атака SQL-injection происходит, когда код приложения или базы данных динамически генерирует запросы, объединяя команду с введенными данными пользователя. Пользователь вводит информацию через интерфейс приложения, которая она становится частью SQL команды и выполняется в базе данных. Давайте посмотрим на примере, рисунок 1 показывает простое приложение с одним пользовательским полем ввода.

Рисунок 1. Ввод идентификатора пользователя в пользовательский интерфейс 

Приложение возвращает список фильмов, которые пользователь взял напрокат. Пользователь вводит идентификатор учетной записи и нажимает Enter. Приложения Приложение или базы данных, объединяет логин с предопределенной командой SELECT так, чтобы логин становится частью условия WHERE. Если пользователь предоставляет правильный логин, список фильмов, возвращается в интерфейсе и все счастливы.

Теперь предположим, что хакер хочет проникнуть в систему для получения данных или нанести ущерб. Например, хакер может попытаться удалить все данные из таблицы аренды (предполагается, что хакер может получить имя таблицы через отдельный хак). Вместо предоставления простого идентификатора пользователя, хакер мог бы также добавить команду TRUNCATE TABLE, как показано на рисунке 2.

Рисунок 2. Ввод изгоев код в пользовательском интерфейсе

Обратите внимание, что значение, введенное в пользовательский интерфейс, теперь включает в себя точку с запятой, а затем команду TRUNCATE TABLE. Поскольку SQL Server поддерживает точку с запятой в качестве разделителя команд и поддерживает несколько команд в блоке, хакер может легко отправить эти команды в базу данных. В результате, таблица аренды будет удалена.

Это, конечно, является очень простым сценарием, но он иллюстрирует логику нападения SQL инъекции. Фокус в том, чтобы убедиться, что этого не может произойти, именно поэтому данное руководство может помочь в том, что нельзя делать.

Практика предотвращения SQL-injection

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

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

Использование хранимых процедур

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

Несмотря на эти преимущества, хранимых процедур самих по себе не достаточно, чтобы защититься от SQL-injection. Они должны быть частью общей стратегии защиты от подобных атак. Тем не менее, некоторые хранимые процедуры являются более безопасными в использовании, чем другие. Например, статические хранимые процедуры не имеют параметров и, следовательно, не могут использоваться для инъекции вредоносного кода. Хранимых Хранимые процедуры, которые содержат только параметризованные команды SQL, также устойчивы к SQL инъекции, поскольку данные команд хранятся отдельно от самой команды. Другими словами, необходимо избегать динамического SQL в хранимых процедурах, когда это возможно.

Используйте динамический SQL только тогда, когда вы не можете избежать этого

Динамический SQL может значительно увеличить риск атаки SQL-injection, когда команда языка объединяется с пользовательскими данными. В некоторых случаях, однако, не возможно избежать динамического SQL. Например, вы можете определить хранимую процедуру, которая создает логин в базе данных, где логин передается в качестве параметра. Проблема в том, что заявление CREATE LOGIN не принимает значение переменной для имени, таким образом вы вынуждены построить вашу команду динамически и при этом пройти проверку синтаксиса ядром базы данных.

Один из способов помочь смягчить риски, связанные с динамическим SQL – корректно экранировать пользовательский ввод. Экранированию пользовательских значений помогают специальные безвредные символы, которые могут быть переданы на вход, (такие как скобки или одинарные кавычки). При использовании с другими элементами языка, эти символы, при использовании с другими элементами языка могут представлять угрозу для базы данных, когда объединяются в статической части SQL запроса. Чтобы избежать этих символов, используйте функции QUOTENAME или REPLACE по мере необходимости для обработки идентификаторов и строковых значений. При использовании какой-либо функции, убедитесь, что правильно рассчитали длину буфера для использования экранирующих символов, иначе вы подставите себя для атаки через усечение, (один из типов атаки SQL-injection, который использует усечение для инъекции вредоносного кода).

Другим способом предотвращения SQL-injection является использование системной хранимой процедуры sp_executesql, вместо оператора EXECUTE, для выполнения динамических запросов. С помощью хранимой процедуры sp_executesql, у вас есть способ использовать параметризацию динамического запроса, так что с данные остаются отдельно от команд языка. Но убедитесь, что правильно используете хранимую процедуру, не используйте ее в качестве простой замены EXECUTE. Вы должны включить параметры в определение команды при его создании и когда вы вызываете хранимую процедуру sp_executesql.

Используйте принцип наименьших привилегий при предоставлении доступа к базам данных

Даже если вы можете ограничить приложения доступом к хранимым процедурам и избежать использования динамического SQL, вы все равно должны убедиться, что доступ к базе данных ограничивается в полной мере. Одним из ваших лучших средств защиты является следование стратегии наименьших привилегий. Каждой учетной записи базы данных должны быть назначены минимальные права, необходимые для доступа к данным. Именно поэтому ограничение доступа к хранимым процедурам может быть настолько эффективным. В идеале, вы предоставляете право выполнить процедуры и запрещаете доступ к чему-либо еще. Если вы позволяете приложению выполнить SQL запросы напрямую, приложение должно использовать учетные записи с наименьшими привилегиями и, с четким указанием того, что учетная запись может читать и/или изменять в базе данных. Ни при каких обстоятельствах вы не должны назначить учетной записи привилегии администратора (например, sysadmin) в приложении.

Даже внутри хранимых процедур, вы должны следовать стратегии минимального доступа. Например, если вы используете оператор EXECUTE AS, для запуска SQL запросов в процедуре, используйте учетную запись с минимальными привилегиями. Если высокопривилегированная операция должна быть выполнена, создайте хранимые процедуры для выполнения этой операции и подпишите хранимые процедуры с помощью сертификата. Цель состоит в том, чтобы гарантировать, что даже если злоумышленник обнаружит дыру в безопасности приложения, он мало что мог сделать. Приложение, имеющее доступ к БД, всегда должно быть ограничено низким уровнем привилегий учетной записи, имеющей минимальные права для выполнения запросов, выполняемых в базе данных.

Использование тестирования и мониторинга для защиты от SQL-инъекций

Независимо от того, насколько тщательны вы были в защите от атак SQL-injection, вы все равно должны запускать код базы данных через необходимые проверки, чтобы убедиться – это безопасно. Начните с проверок кода, которые специально проверяют код его на восприимчивость к SQL-injection, таких как неправильное использование динамического SQL. Отсюда вы можете перейти к фазе проверки качества. В дополнение к любому нормальному тестированию и проверки процессов, которые будут выполняться в базе данных, вместе с тем поддерживаемый код должен быть подвергнут попытке SQL-injection, чтобы попробовать найти уязвимости. Процесс тестирования должен включать все уровни SQL-injection, в том числе попытку усечения данных. Наконец, когда база данных используется, лог-файлы и другие устройства слежения должны быть использованы для мониторинга баз данных для любых признаков SQL-injection.

Защита от атак SQL инъекции

Принципы, предложенные выше, только затрагивают основные темы, но они должны направить вас в правильном направлении. Учитывая распространение мобильных приложений и растущую потребность синхронизировать данные между несколькими устройствами, необходимо проявлять бдительность больше, чем когда-либо. Даже одна уязвимость поставит вашу базу в зону риска, а безопасность данных – не место для халтуры. Разработчики баз данных и разработчики приложений должны работать вместе, чтобы избежать таких уязвимостей. Атаки SQL-injection могут быть предотвращены, но только если вы предпримете необходимые шаги для защиты вашей системы.

ОТДЫХ : Беларусь, Орша

29-го числа мы были в Беларуси, тут нами была намечена первая остановка, в г. Орша.
Я конечно понимаю, что описывая Беларусь, буду не объективен, особенно учитывая тот факт что это первая поездка за границу на автомобиле, но первое впечатление эта страна производит положительное.
Чистые и широкие улицы, ухоженные (по крайней мере покрашенные) дома.
Люди на улицах улыбаются.

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

В общем о Беларусии у меня только положительные впечатления.

понедельник, 31 декабря 2012 г.

ОТДЫХ : Граница Россия - Беларусь

Я не знаю как можно ее описать....
Наверное словами: ее нет. Мы просто проехали оба погранпоста, почти не сбавляя скорости.
На российской скороне кажется не было даже пограничников. Уже не помню это все было 29-го декабря.
Белоруская сторона просто махнула жезлом чтоб не тормозил, скорость была где-то 30-50км/ч.

вторник, 25 декабря 2012 г.

MSSQL : Уровни изоляции в MS SQL - REPEATABLE READ

Сегодня попробую рассказать о блокировке REPEATABLE READ (повторяющееся чтение)

Начнем с определений:

Определение INTUIT
REPEATABLE READ – повторяющееся чтение. Повторное чтение строки возвратит первоначально считанные данные, несмотря на любые обновления, произведенные другими пользователями до завершения транзакции. Тем не менее на этом уровне изоляции возможно возникновение фантомов. Его установка реализуется командой:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

Определение WIKIPEDIA
Уровень, при котором чтение одной и той же строки или строк в транзакции дает одинаковый результат. (Пока транзакция не завершена, никакие другие транзакции не могут модифицировать эти данные.)

Определение Microsoft
REPEATABLE READ - Указывает на то, что инструкции не могут считывать данные, которые были изменены, но еще не зафиксированы другими транзакциями, а также на то, что другие транзакции не могут изменять данные, читаемые текущей транзакцией, до ее завершения.
Разделяемые блокировки применяются ко всем данным, считываемым любой инструкцией транзакции, и сохраняются до ее завершения. Это запрещает другим транзакциям изменять строки, считываемые текущей транзакцией. Другие транзакции могут вставлять новые строки, соответствующие условиям поиска инструкций, содержащихся в текущей транзакции. При повторном запуске инструкции текущей транзакцией будут извлечены новые строки, что приведет к считыванию фантома. Учитывая то, что разделяемые блокировки сохраняются до завершения транзакции и не снимаются в конце каждой инструкции, степень совпадений ниже, чем при уровне изоляции по умолчанию READ COMMITTED. Используйте этот аргумент только в случае необходимости.

Ужасные определения! Фантомы, блокировки, транзакции... Намешана каша... Конечно я понимаю что значит эта блокировка, но когда пытаюсь вникнуть в эти определения, то крыша легонько едет. Давайте попробуем вместе разобраться, что к чему. Начнем с основного - cоздадим таблицу и заполним ее.

  1. IF (OBJECT_ID('tmp_isolation_level') IS NOT NULL) DROP TABLE [dbo].[tmp_isolation_level]
  2. GO
  3. CREATE TABLE [dbo].[tmp_isolation_level] ( [rowid] int IDENTITY (1,1), [textvalue] varchar (100))
  4. GO
  5. INSERT INTO [dbo].[tmp_isolation_level] ([textvalue])
  6. SELECT '111111111111'
  7. UNION ALL
  8. SELECT '222222222222'
  9. UNION ALL
  10. SELECT '333333333333'
  11. UNION ALL
  12. SELECT '444444444444'
  13. UNION ALL
  14. SELECT '555555555555'
  15. UNION ALL
  16. SELECT '666666666666'
  17. GO

Теперь приступим в практическому изучению что будет происходить :)
Повторяющееся чтение нам гарантирует неизменность уже прочитанных данных, до завершения транзакции. Т.е. если параллельный запрос попытается их изменить, то это действие будет заблокировано ядром базы, например:
Поток 1Поток 2Комментарий
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
GO
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
GO
Устанавливаем уровень изоляции.
В данном примере нам не важно какой уровень изоляции будет на 2-м потоке, поэтому я использую значение по умолчанию или "READ COMMITTED"
BEGIN TRANSACTION BEGIN TRANSACTION Открываем транзакции
SELECT * FROM[tmp_isolation_level] - Читаем таблицу в первом потоке (тут все хорошо)
- SELECT * FROM [tmp_isolation_level] Читаем таблицу во втором потоке (тут все хорошо)
- update [tmp_isolation_level]
set [textvalue] = '343434343434'
where [rowid] = 4
Пытаемся внести изменения в данные, во втором потоке.
В этом месте 2-й запрос блокируется 1-м и ожидает завершения транзакиции 1-го потока
COMMIT TRANSACTION - Завершение транзакции 1-го потока разблокирует ресурс (таблицу).
Записываются изменения 1-го потока
- update [tmp_isolation_level]
set [textvalue] = '343434343434'
where [rowid] = 4
Выполняется разблокированный UPDATE
- COMMIT TRANSACTION Завершение транзакции 2-го потока, записываются изменения 2-го потока

Теперь предлагаю рассмотреть немного другой пример, тут мы проследим что произойдет если изменения будут вноситься в 1-м потоке.

Поток 1 Поток 2 Комментарий
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
GO
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
GO
Устанавливаем уровень изоляции
BEGIN TRANSACTION BEGIN TRANSACTION Открываем транзакции
SELECT * FROM [tmp_isolation_level] - Читаем таблицу в первом потоке (тут все хорошо)
- SELECT * FROM [tmp_isolation_level] Читаем таблицу во втором потоке (тут все хорошо)
UPDATE [tmp_isolation_level]
SET [textvalue] = '343434343434'
WHERE [rowid] = 4
- Пытаемся внести изменения в данные, в первом потоке, но данные являются заблокированными
в этом месте 1-й запрос блокируется 2-м и ожидает завершения транзакиции 2-го потока
- UPDATE [tmp_isolation_level]
SET [textvalue] = '343434343434'
WHERE [rowid] = 4
Хорошо, пробуем внести изменения данных во 2-м потоке.
НО, для 2-го потока данные тоже заблокированы....
Сообщение 1205, уровень 13, состояние 45, строка 2
Транзакция (идентификатор процесса 222) вызвала взаимоблокировку ресурсов блокировка с другим процессом и стала жертвой взаимоблокировки. Запустите транзакцию повторно.
- В одном из потоков вылетает ошибка о взаимоблокировке.
Т.е. 1-й и 2-й потоки заблокировали друг друга.
Ядро базы обнаруживает этот факт, прерывает один из потоков, и завершает второй.
Прерваный поток завершается с откатом изменений (ROLLBACK TRANSACTION)
- COMMIT TRANSACTION Прерывание 1-го потока разблокирует 2-й, а он в свою очередь завершается без ошибок.
- Выполнение команд успешно завершено. -

Вот так, вкратце работает REPEATABLE READ.

Успехов вам на поприще программирования SQL.

Источники:
Уровни изоляции в ядре СУБД (MSDN)
SET TRANSACTION ISOLATION LEVEL (Transact-SQL) (MSDN)
Настройка уровня изоляции транзакции (MSDN)
Уровень изолированности транзакций (Википедия)
Уровни изоляции и несогласованность данных (T-SQL.RU)
Уровни изоляции транзакций в SQL. Шпаргалка (Arbinada.com)
Уровни изоляции транзакций в SQL («Мир ПК» , № 07, 2009)

понедельник, 24 декабря 2012 г.

МЕНЕДЖМЕНТ : Организационная политика

Сегодня хочу привести выдержку из книги «IT проекты: фронтовые очерки», связанную проблемами возникающими при построении системы.
Поскольку люди не склонны расставаться с властью и влиянием, процесс сборки превращается в политическую игру. Это порождает бессчетные дискуссии о том, кто и какие будет иметь права и обязанности в интересах процесса сборки. Во время таких дискуссий обнажаются все негативные политические тенденции в организации.
Ревнители чистоты воскликнут, что политические устремления достойны только осуждения и им надо всячески препятствовать: работа, мол, достаточно трудна с технической точки зрения и без «загрязнения» ее политикой. Однако в большинстве организаций желание устранить политику не обязательно приводит к ее реальному устранению. Политика – это неотъемлемая часть окружающего нас реального мира, и с ней приходится иметь дело. Вы должны пройти через этот этап, каким бы неприятным он ни казался.
Политика политике рознь
С моей точки зрения, политика политике рознь. С одной стороны, есть «хорошая политика»– нечто сродни понятию «честной борьбы» – и здоровый политический процесс может и должен помогать принимать правильные решения. С другой стороны, существует «плохая политика», в результате которой цели и действия организации могут подчиниться карьерным интересам отдельных личностей, и политику такого сорта необходимо затаптывать на корню. И конечно же, есть еще проблема «серой зоны» – зоны между «хорошим» и «плохим».

пятница, 21 декабря 2012 г.

ОТДЫХ : Получение визы (чать 2)

Сегодня жена съездила и получила наши визы.

По разговорам в очереди я помню, что народ упоминал то что в Литовском посольстве забывают выдать визу на ребенка. У нас все обошлось, все нормально, жалоб нет:).

МЕНЕДЖМЕНТ : Изучайте языки программирования

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

Знаете мне также приходилось сталкиваться с различными языками программирования, например, Basic, Pascal/Object Pascal/Delphi, C/C++/C#, Perl, PHP и мой любимый SQL.
Я вспоминаю как еще в 1997 году занялся изучением Pascal, для глубокого погружения мною была написана игра "Монополия".
Для реализации мне пришлось изучить работу с графикой, прерывания, для подключения мышки, реализовать простой ИИ, и тогда мне не было еще и 15 лет.
В то время я думал что могу все. На такое глубокое погружение у меня тогда ушло где-то 2 месяца.
Дальше был C и C++, тут было и проще и сложнее, задачей я выбрал реализацию нескольких сортировок и поисков в массиве. Тоже использовал графику для визуализации сравнения скорости поиска, для создания интерактивого взаимодействия с пользователем реализовывал меню, как графическое, так и текстовое.
И так далее и тому подобное....
Сейчас я в основном пишу на SQL по работе, а для себя что-нибудь на Perl/PHP/C++, просто чтобы не терять навык.
Что и Вам советую.