Я подписался на различные группы пользователей конкурирующих инструментов абстракции базы данных jOOQ . Одним из них является ActiveJDBC , реализация Java шаблона проектирования Active Record . Его сопровождающий Игорь Полевой недавно заявил, что:
SQL-инъекция — это проблема веб-приложения, которая не связана напрямую с ORM. ActiveJDBC обработает любой SQL, который ему передан.
(См. Обсуждение здесь: https://groups.google.com/d/topic/activejdbc-group/5D2jhWuW4Sg/discussion )
Это действительно так? Должен ли уровень абстракции базы данных делегировать предотвращение внедрения SQL клиентскому приложению?
Фон SQL-инъекций
SQL-инъекция — это проблема, с которой большинству из нас, разработчикам, приходилось сталкиваться в своей профессиональной жизни. Википедия хорошо объясняет проблему . Учитывая следующий фрагмент кода Java (или любой другой язык):
statement = "SELECT * FROM users WHERE name = '" + userName + "';"
Представьте, что «userName» — это переменная, взятая из HTTP-запроса . Слепое вставление параметра HTTP-запроса уступает простым атакам:
-- attacker sends this code in the userName field: userName = "a';DROP TABLE users; SELECT * FROM userinfo WHERE 't' = 't" -- resulting in the following statement: statement = "SELECT * FROM users WHERE name = 'a';" + "DROP TABLE users;" + + "SELECT * FROM userinfo WHERE 't' = 't';"
Это с тобой не случается?
Возможно, нет. Но проблема часто встречается в переполнении стека . Более 2000 результатов при поиске «SQL-инъекция»: http://stackoverflow.com/search?q=sql+injection . Так что, даже если вы знаете, как это предотвратить, кто-то в вашей команде не может. Да, но …
это не что плохо , если один из 500 заявлений плохо написано каким — то программист , который не замечал эту угрозу?
Подумай еще раз. Вы когда-нибудь слышали об инструменте под названием sqlmap ? Этот инструмент найдет любую проблемную страницу в вашем приложении в течение нескольких секунд / минут / часов, в зависимости от серьезности проблемы с инъекцией. Мало того, что, найдя проблемные страницы, он сможет извлекать ВСЕ виды данных из вашей базы данных. Я имею в виду ВСЕ виды данных. Выбор функций sqlmap:
- Поддержка перечисления пользователей, хэшей паролей, привилегий, ролей, баз данных, таблиц и столбцов .
- Поддержка поиска определенных имен баз данных, определенных таблиц по всем базам данных или определенных столбцов по всем таблицам баз данных . Это полезно, например, для идентификации таблиц, содержащих пользовательские учетные данные приложения, где имена соответствующих столбцов содержат такие строки, как name и pass.
- Поддержка загрузки и выгрузки любого файла с сервера базы данных, лежащего в основе файловой системы, если в качестве программного обеспечения базы данных используется MySQL, PostgreSQL или Microsoft SQL Server.
- Поддержка для выполнения произвольных команд и получения их стандартного вывода на сервере базы данных, лежащем в основе операционной системы, когда программным обеспечением базы данных является MySQL, PostgreSQL или Microsoft SQL Server.
Да! Если вы страдаете от небезопасного кода для SQL-инъекций, злоумышленник может захватить ваш сервер при некоторых обстоятельствах !! В нашей компании мы опробовали sqlmap в среде «песочницы» против некоторых программ с открытым исходным кодом для блогов с известными уязвимостями. Нам удалось захватить сервер в кратчайшие сроки, не написав ни одной строки SQL
Абстракция базы данных и SQL-инъекция
Хорошо, теперь, когда я обращаю ваше внимание, давайте еще раз подумаем о том, что сказал Игорь Полевой:
SQL-инъекция — это проблема веб-приложения, которая не связана напрямую с ORM. ActiveJDBC обработает любой SQL, который ему передан.
Да, он может быть прав. Учитывая, что ActiveJDBC — это тонкая оболочка для JDBC, позволяющая делать хорошие упрощения CRUD, такие как эти (взяты с их сайта):
List<Employee> people = Employee.where("department = ? and hire_date > ? ", "IT", hireDate) .offset(21) .limit(10) .orderBy("hire_date asc");
Вы заметили риск внедрения SQL? Правильно. Даже если он использует значения связывания для базовых PreparedStatements, этот инструмент так же небезопасен, как и JDBC. Вы можете избежать внедрения SQL, если будете осторожны. Или вы можете начать объединять строки повсюду. Но вы должны знать об этом! Как jOOQ справляется с подобными ситуациями? Руководство jOOQ объясняет, как значения привязки обрабатываются явно или неявно. Вот некоторые примеры:
// Implicitly creating a bind value for "Poe" create.select() .from(T_AUTHOR) .where(LAST_NAME.equal("Poe")); // Explicitly creating a (named) bind value for "Poe" create.select() .from(T_AUTHOR) .where(LAST_NAME.equal(param("lastName", "Poe"))); // Explicitly inlining "Poe" in the generated SQL string create.select() .from(T_AUTHOR) .where(LAST_NAME.equal(inline("Poe")));
Приведенные выше примеры приведут
SELECT * FROM T_AUTHOR WHERE LAST_NAME = ? SELECT * FROM T_AUTHOR WHERE LAST_NAME = ? SELECT * FROM T_AUTHOR WHERE LAST_NAME = 'Poe'
В случае, когда «Poe» встроено, экранирование обрабатывается jOOQ, чтобы предотвратить синтаксические ошибки и внедрение SQL. Но jOOQ также поддерживает внедрение строк SQL непосредственно в сгенерированный SQL. Например:
// Inject plain SQL into jOOQ create.select() .from(T_AUTHOR) .where("LAST_NAME = 'Poe'");
В этом случае SQL-инъекция может происходить так же, как с JDBC.
Вывод
По сути, Игорь прав. Разработчик (клиентского) приложения должен знать о проблемах внедрения SQL, создаваемых их кодом. Но если инфраструктура абстракции базы данных, построенная на основе JDBC, сможет максимально избежать внедрения SQL в его API, тем лучше. С точки зрения внедрения SQL-кода структуры абстракции базы данных можно разделить на три категории:
- Простые утилиты . К ним относятся Spring JdbcTemplate или Apache DbUtils . Они действительно просто улучшают JDBC API с удобством (меньше обработки исключений, меньше многословия, более простое связывание переменных, более простая выборка данных). Конечно, эти инструменты не помешают внедрению SQL
- Полная SQL абстракция . К ним относятся jOOQ , JaQu , QueryDSL , JPA CriteriaQuery и другие. Их обычный режим работы всегда будет отображать значения связывания в сгенерированном SQL. Это предотвращает внедрение SQL в большинстве случаев.
- Остальные . Многие другие платформы (включая ActiveJDBC и Hibernate ) в основном основаны на (SQL или HQL) строковых операциях. Хотя они абстрагируют многие вещи, связанные с SQL, они вообще не предотвращают внедрение SQL.
Поэтому, когда вы выбираете какой-либо инструмент абстракции SQL в своем приложении Java, остерегайтесь серьезности внедрения SQL. И будьте осторожны с фактом, поможет ли ваш инструмент предотвратить это или нет!