Повышение безопасности и производительности приложений DB2 Ruby On Rails с использованием параметризованных запросов

Новый адаптер ActiveRecord для DB2

В связи с ростом интереса к Ruby On Rails со стороны предприятий некоторые наблюдатели задаются вопросом о его пригодности, когда речь заходит о высоких требованиях, предъявляемых к корпоративному ПО. Одна из проблем заключается в том, что ActiveRecord, объектно-реляционная привязка (Object-Relational Mapper – ORM) Rails, не использует заготовленные операторы – во всяком случае, не использовала их до сих пор. В последней версии DB2® on Rails автоматически доступны параметризованные запросы, которые повышают производительность и безопасность приложений Rails.

Антонио Каньяно, программист и популяризатор, IBM

Фото Антонио КаньяноАнтонио Каньяно (Antonio Cangiano) работает программистом и популяризатором в подразделении DB2 Toronto Software Lab IBM. Он – создатель адаптера Rails для DB2 и один из ведущих участников сообщества DB2 on Rails. Он хорошо известен в кругах разработчиков Ruby и Rails и в 2009 году написал книгу "Ruby On Rails для разработчиков Microsoft", посвященную Wrox. Подробнее об Антонио можно узнать из его блога Zen and the Art of Programming.



02.11.2011

Ruby On Rails стала одной из наиболее популярных сред разработки Web-приложений. Выпущенная в 2004 году, эта среда быстро эволюционирует, привлекает большое внимание средств массовой информации и собрала широкое сообщество в кругах разработчиков.

Всего за несколько лет Rails (как ее обычно называют) превратилась из передовой технологии, с которой работала горстка пользователей первой волны и молодых компаний, в зрелый инструмент, достоинства которого в последнее время стали заражать более "корпоративно ориентированную" публику.

Rails и предприятие

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

Тем не менее, имеет смысл переформулировать этот вопрос, спросив, готов ли корпоративный мир к применению Rails. За последние несколько лет корпоративный мир начал воспринимать живое движение мира разработки ПО и применять более легкие инструменты, но несогласованные требования еще остаются, что делает Ruby On Rails мало пригодным во многих сценариях.

К счастью, Rails предлагает систему дополнений, что позволило создать тысячи плагинов, разработанных сообществом для удовлетворения самых разнообразных требований. Но в основе своей Rails старается следовать принципу "простейшего (возможно) работоспособного решения", что резко контрастирует с подходом, часто предпочтительным для предприятия.

Так, например, если в среде разработчиков программ с открытым исходным кодом популярны и часто достаточны системы SQLite и MySQL, то корпоративные разработчики гораздо больше заинтересованы в надежной поддержке коммерческих баз данных, таких как DB2 и Oracle.

IBM® уже давно пошла по пути сближения этих двух миров. Фактически, IBM – единственный поставщик СУБД, предоставляющий коммерческую поддержку драйвера Ruby и адаптера Rails для DB2 и IBM Informix® Dynamic Server (IDS). Благодаря этому многие компании, использующие в своей инфраструктуре DB2, смогли разработать новые приложения с использованием Ruby On Rails. Так называемая пара "DB2 on Rails" очень удобна также и для разработчиков ПО с открытым исходным, кодом и для молодых компаний, которым хочется объединить мощный, масштабируемый, надежный (и бесплатный в своей редакции Express-C) сервер баз данных с простотой написания приложений, характерной для Ruby on Rails.

Сегодня, когда вышла версия 2.0 адаптера Rails, DB2 стала также единственной базой данных, которая прозрачно поддерживает параметризованные запросы в Rails (без необходимости изменять код приложения). Это оказывает глубокое влияние на производительность и безопасность и является важным шагом вперед для любого разработчика, который использует Rails в сочетании с DB2.


Параметризованные запросы и ActiveRecord

За кулисами типичное Web-приложение вновь и вновь выполняет большое число аналогичных запросов. В некоторых случаях меняется не сам запрос, а используемые в нем значения. Например, запросы, приведенные в листинге 1, идентичны за исключением запрашиваемого имени.

Листинг 1. Аналогичные SQL-запросы
SELECT * FROM people WHERE name = 'Antonio'
SELECT * FROM people WHERE name = 'Leon'
SELECT * FROM people WHERE name = 'Praveen'
SELECT * FROM people WHERE name = 'Mario'

Все они могут быть объединены в один параметризованный запрос (заготовленный оператор), как показано в листинге 2.

Листинг 2. Параметризованный запрос
SELECT * FROM people WHERE name = ?

Фактическое значение передается предварительно скомпилированному запросу в качестве параметра во время исполнения. Сам запрос и его план доступа однажды кэшируются DB2 и затем готовы к использованию при каждом исполнении запроса. Это повышает производительность, так как база данных экономит все накладные расходы, связанные с расчетом плана выполнения одного и того же вновь и вновь повторяющегося запроса. Если такой (или более сложный) запрос повторяется несколько сотен (или тысяч) раз, разница между этими двумя подходами становится весьма значительной.

Rails-приложения используют объектно-реляционную привязку (ORM) ActiveRecord для обработки соединений базы данных и запросов. По умолчанию ActiveRecord не поддерживает параметризованные запросы. Это означает, что каждый запрос создается посредством динамического слияния данных, вводимых пользователем (которые, как правило, должным образом продезинфицированы) с последующим выполнением в виде самостоятельного запроса. Например, ActiveRecord переводит следующие вызовы метода (листинг 3) в упомянутые выше самостоятельные запросы (см. листинг 1).

Листинг 3. ActiveRecord-эквивалент листинга 1
Person.find_by_name('Antonio')
Person.find_by_name('Leon')
Person.find_by_name('Praveen')
Person.find_by_name('Mario')

Благодаря новейшему пакету Ruby для DB2 on Rails (называемому ibm_db), каждый из этих запросов выполняется адаптером ActiveRecord (который был разработан IBM для DB2) таким образом, чтобы создать единый параметризованный запрос, немедленно готовый к повторному использованию. Кроме производительности, параметризованные запросы отлично отражают атаки SQL-инъекций. Параметры рассматриваются как переменные, передаваемые запросу, которые никак не влияют на структуру самого запроса. Таким образом, хитроумные трюки с кавычками и специальными символами, которые злоумышленники иногда пытаются применять для динамического изменения структуры запроса, становятся бесполезными.

ActiveRecord уже выполняет полезную работу по санитарной обработке вводимых пользователем данных, позволяя разработчику сосредоточиться на применении подходящих инструментов, предоставляемых средой. Например, ActiveRecord правильно очистит от прямых SQL-инъекций следующую инструкцию (листинг 4).

Листинг 4. Безопасное обращение с входными данными в ActiveRecord
User.find(:all, :conditions => ["role = ? AND age > ?", role, age])

Если не очень аккуратный разработчик прибегнет к тексту из листинга 5 (в надежде непосредственно встраивать значения), такой вызов будет уязвим для SQL-инъекций.

Листинг 5. Небезопасное обращение с входными данными в ActiveRecord
# Don't do this
User.find(:all, :conditions => "role = '#{role}' AND age > #{age}")

В этом случае запрос формируется динамически в зависимости от значений параметров role и age. Например, в поле age (возраст) можно ввести строку "18 OR 1=1", и запрос станет примерно таким (листинг 6).

Листинг 6. Атака SQL-инъекции
SELECT * FROM users WHERE role = 'user' AND age > 18 OR 1=1

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

Уже по одной этой причине разработчикам всегда следует выбирать безопасные варианты, предлагаемые ActiveRecord для дезинфекции ввода (как показано в листинге 4). Новая редакция DB2 on Rails добавляет дополнительный уровень безопасности благодаря тому, что эти "безопасные" вызовы переводятся в параметризованные запросы, которые не боятся атак SQL-инъекции. Работая с DB2, вы можете быть спокойны, зная, что если хитроумный хакер сумеет обойти санитарный контроль, выполняемый ActiveRecord, то эти лишние символы или злонамеренные кавычки все равно не изменят характер вашего запроса.


Установка или обновление до ibm_db 2.0.0

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

  • установить последнюю версию пакета Ruby для DB2 on Rails (ibm_db);
  • изменить файл конфигурации приложения базы данных.

Итак, приступим.

Пользователи Microsoft® Windows® могут легко установить пакет, выполнив следующую команду из командной строки (листинг 7):

Листинг 7. Установка пакета ibm_db gem на Windows
C:\> gem install ibm_db

Если вы пользователь Linux® или UNIX®, то перед установкой пакета необходимо указать, где находятся файлы для разработки, как это сделано в листинге 8.

Листинг 8. Установка пакета ibm_db на Linux/AIX®
$ sudo -s
$ export IBM_DB_INCLUDE=/home/db2inst1/sqllib/include
$ export IBM_DB_LIB=/home/db2inst1/sqllib/lib
$ . /home/db2inst1/sqllib/db2profile
$ gem install ibm_db

(Пользователи 64-разрядной версии должны вместо этого указать путь к библиотеке lib64.)

Тем, кто работает на Mac OS X 10.5 (Leopard), следует установить пакет, как указано в листинге 9.

Листинг 9. Установка пакета ibm_db на Mac OS X 10.5
$ sudo -s
$ export IBM_DB_LIB=/Users/<username>/sqllib/lib
$ export IBM_DB_INCLUDE=/Users/<username>/sqllib/include
$ . /Users/<username>/sqllib/db2profile
$ gem install ibm_db

Если же вы – пользователь Mac OS X 10.6 (Snow Leopard), вам следует руководствоваться листингом 10.

Листинг 10. Установка пакета ibm_db на Mac OS X 10.6
$ sudo -s
$ export IBM_DB_LIB=/Users/<username>/sqllib/lib64
$ export IBM_DB_INCLUDE=/Users/<username>/sqllib/include
$ export ARCHFLAGS="-arch x86_64"
$ gem install ibm_db

Все эти инструкции устанавливают пакет или обновляют его до последней версии, если уже установлена более ранняя версия. Если команда gem install не работает с установленной версией RubyGems, можно выполнить следующую команду, чтобы обновить сам менеджер пакетов (листинг 11).

Листинг 11. Обновление RubyGems
$ gem update --system

Включение параметризованных запросов в существующие приложения Rails

Rails-приложения хранят конфигурацию базы данных в файле, расположенном в файле config/database.yml. Для того чтобы разрешить параметризованные запросы в данном приложении, укажите параметр parameterized. Например, как в листинге 12.

Листинг 12. Пример фрагмента конфигурации единой среды
production:
 adapter: ibm_db
 username: db2inst1
 password: secret
 database: mydb
 parameterized: true

Если этот параметр конфигурации не установлен, адаптер ActiveRecord для DB2 будет продолжать работать как в предыдущих версиях, не превращая обычные запросы в параметризованные. Это позволяет быстро оценить прирост производительности и решить, включать ли эту опцию в производственном режиме.


Соображения производительности

Конечно, нужно обязательно провести свои собственные испытания, но тесты, выполненные в нашей лаборатории, показывают, что включение параметризованных запросов значительно повышает производительность среды. Преимущества заготовленных операторов наглядно проявляются с повышением рабочей нагрузки. Диаграмма на рисунке 1 показывает результаты, полученные при тестировании относительно тяжелой нагрузки с включенными параметризованными запросами и без них, а также с включенной функцией Statement Concentrator.

Рисунок 1. Результаты тестирования
Диаграмма результатов испытаний, на которой сравниваются транзакции с течением времени

Как видите, включение параметризованных запросов повысило пропускную способность базы данных на 30-40% и даже обеспечило 15-25%-ное повышение по сравнению с режимом Statement Concentrator. Statement Concentrator можно рассматривать как промежуточный шаг. Это функция, которая пытается добиться преимуществ, достигаемых за счет заготовленных операторов, на уровне сервера баз данных, предоставляя общий план доступа для идентичных запросов (за исключением значений литералов), что сокращает накладные расходы, связанные с компиляцией. Это отличная функция, доступная только в DB2 9.7, которую следует активизировать, если параметризованные запросы не подходят для данной среды разработки. К счастью, разработчикам DB2 on Rails больше не придется беспокоиться об этом.


Заключение

Выпуск новой версии пакета ibm_db устраняет один из очень немногих (но, тем не менее, существенных) недостатков Rails и должен стать хорошей новостью для всех, кто заинтересован в объединении простоты Rails с мощью базы данных мирового класса. DB2 с ее широкими функциональными возможностями, включая стандартную поддержку хранения XML (pureXML), прокладывает путь, делая Rails-приложения масштабируемыми на корпоративном уровне. К тому же DB2 делает это при непревзойденно низкой цене благодаря абсолютно бесплатной версии DB2 Express-C.

Ресурсы

Научиться

  • Оригинал статьи (EN).
  • Блог DB2 on Rails: узнайте больше, посещая блог, посвященный DB2 on Rails.
  • Руководства по Ruby on Rails: прочтите эти руководства и начните работать с Ruby on Rails.
  • Getting Started with DB2 Express-C (IBM, 2009 г.): прочтите эту бесплатную электронную книгу, которая идеально подходит для разработчиков, консультантов, независимых производителей ПО, администраторов баз данных, студентов и всех, кто осваивает DB2 (EN).
  • Видеозаписи DB2 on Campus: изучите DB2 за один день с помощью этих видеозаписей DB2 on Campus и соответствующих презентаций в формате PDF.

Получить продукты и технологии

  • DB2 Express-C: загрузите DB2 Express-C, полностью лицензионный продукт, предлагаемый сообществу разработчиков бесплатно.
  • IBM Data Studio: загрузите Data Studio.

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Information Management, Open source
ArticleID=769250
ArticleTitle=Повышение безопасности и производительности приложений DB2 Ruby On Rails с использованием параметризованных запросов
publish-date=11022011