Статьи

Абстракция базы данных и SQL-инъекция

Я подписался на различные группы пользователей конкурирующих инструментов абстракции базы данных jOOQ . Одним из них является ActiveJDBC , реализация Java шаблона проектирования Active Record . Его сопровождающий Игорь Полевой недавно заявил, что:

SQL-инъекция — это проблема веб-приложения, которая не связана напрямую с ORM. ActiveJDBC обработает любой SQL, который ему передан.

(См. Обсуждение здесь: https://groups.google.com/d/topic/activejdbc-group/5D2jhWuW4Sg/discussion )


Это действительно так? Должен ли уровень абстракции базы данных делегировать предотвращение внедрения SQL клиентскому приложению?  

Фон SQL-инъекций

SQL-инъекция — это проблема, с которой большинству из нас, разработчикам, приходилось сталкиваться в своей профессиональной жизни. Википедия хорошо объясняет проблему . Учитывая следующий фрагмент кода Java (или любой другой язык):

1
statement = "SELECT * FROM users WHERE name = '" + userName + "';"

Представьте, что «userName» — это переменная, взятая из HTTP-запроса . Слепое вставление параметра HTTP-запроса уступает простым атакам:

1
2
3
4
5
6
7
-- 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, такие как эти (взяты с их сайта):

1
2
3
4
5
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 объясняет, как значения привязки обрабатываются явно или неявно. Вот некоторые примеры:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
// 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")));

Приведенные выше примеры приведут

1
2
3
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. Например:

1
2
3
4
// 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. И будьте осторожны с фактом, поможет ли ваш инструмент предотвратить это или нет!

Ссылка: Абстракция базы данных и SQL-инъекция от нашего партнера по JCG Лукаса Эдера из блога JAVA, SQL и JOOQ .