Pull to refresh
0
Rating

OWASP TOP-10: практический взгляд на безопасность веб-приложений: №1 — инъекции

SimplePay corporate blog Information Security *
Recovery mode
Мы рады представить Вам очередную статью из нашей серии о безопасности Web-приложений для непрограммистов и начинающих разработчиков, плохо понимающих проблематику. В этой статье мы поговорим о важности фильтрации данных и таком распространенном и очень опасном типе уязвимостей, как инъекции.

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

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

Все эти объекты, и не только эти, хранятся в таблицах, где каждая строка – 1 объект.

Например, объект «Клиент» может иметь следующий набор полей: id, имя, фамилия, e-mail, мобильный телефон, и храниться в таблице вида:

Таблица clients (Клиенты)
id
(идентификатор)
cl_name
(имя)
cl_sur_name (фамилия) e-mail cell
(мобильный)
other
(и т.п.)
1 Ivan Ivanov ivan@mail +70000000000 42
Суть взаимодействия пользователя с Web-приложением заключается в обмене запросами между браузером и сервером, где браузер отправляет серверу различные параметры и получает от сервера ответ.

Чтобы получить или изменить объекты (например, получить выписку по счету или обновить свою анкету) необходимо запросить ту или иную страницу на сервере (далее по тексту – скрипт). Web-приложения с этой целью используют формы или вызовы непосредственно URL скрипта .

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

Для передачи данных из браузера пользователя на сервер по HTTP-протоколу в основном используются два метода — GET и POST (существуют еще методы PUT и DELETE, но они используются преимущественно в API).

При передаче данных методом GET, все параметры запроса передаются в URL страницы в заголовке HTTP-запроса, например:

http://simplethreats.ru/get_order?order=150

В случае использования метода POST, сервер будет получать данные уже в теле HTTP-запроса, а в URL параметры перечислены не будут. Таким образом, к примеру, отправляется большинство форм, и всегда критичные аутентификационные данные (передача данных в URL небезопасна, ведь записи об URL и заголовки HTTP-запросов остаются в множестве журналов).

Обращения через GET или POST могут производиться к любым объектам, будь то записи в базе данных или же чтение файла (скажем, картинки или скрипта с диска). А так как объектов бизнес-логики в системе может быть очень много и они могут иметь самые различные типы, то и обращений по идентификаторам в рамках одного, даже простого Web-приложения может происходить множество.

С тем, каким образом данные попадают в Web-приложение мы определились, а что же происходит внутри?

Что происходит с параметрами из запроса в приложении


В нашей первой статье мы уже рассказали о том, что, все данные, как правило, хранятся в специальных базах в виде таблиц, обращения к которым строятся в форме текстовых запросов, чаще всего написанных на специальном языке запросов SQL (Structured Query Language – структурированный язык запросов). 

Web-приложения, как правило, строят SQL запросы, сочетающие код написанный разработчиком приложения, с параметрами переданными пользователем. Рассмотрим пример:

SELECT  title, text FROM news WHERE id=$id

В нашем примере, $id – параметр передаваемый пользователем (переменная часть запроса), в то время как остальная часть запроса статическая и была заложена разработчиком приложения. Наличие переменных пользовательских данных в статическом SQL запросе, делает весь запрос динамическим.

В чем суть инъекции?


В случае с SQL, вся суть инъекции в том, чтобы модифицировать параметры HTTP-запроса таким образом, чтобы исказить SQL запрос к базе данных и «подсунуть» его серверу под видом нормального. Это позволит злоумышленнику получить несанкционированный доступ к данным.

Предположим, у нас в базе данных есть таблица «transactions» с данными о транзакциях пользователей. Она содержит следующие поля:

  • «user_id» — Уникальный идентификатор пользователя
  • «date» — Дата
  • «amount» — Сумма
  • «description» — Назначение

Таблица transactions
user_id date amount description
10 2015-05-26 1000
11 2015-05-26 1500
12 2015-05-26 1300
n 2015-05-26 x
Предположим, что наш аккаунт, под которым мы находимся в приложении, имеет идентификатор 10 (user_id=10) и эти данные хранятся в сессии приложения (были записаны туда при авторизации пользователя).

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

Для того чтобы нам получить данные о своих транзакциях за 26 мая 2015г. в кабинете пользователя может использоваться страница со следующим адресом:

http://mybank.simplethreats.ru/transactions.jsp?date=2015-05-26

При вызове которого дата «2015-05-26» будет получена из GET-параметра в URL, а значение user_id будет получено из сессии приложения. На основе этих данных, для получения информации о транзакциях пользователя, приложение сформирует SQL-запрос:

SELECT * FROM transactions WHERE date = "2015-05-26" AND user_id = 10

Для тех, кто не знаком с синтаксисом SQL для лучшего понимания, разберем этот запрос.

Что в запросе


Запрос состоит из оператора SELECT (дословно с англ. – «ВЫБРАТЬ»), который используется для выбора данных из таблицы. Существуют еще операторы UPDATE, INSERT, DELETE, которые, как нетрудно догадаться из их названий, выполняют операции обновления, вставки и удаления строк соответственно.

Символ «*» означает, что мы выбираем все столбцы таблицы. Далее следует ключевое слово FROM (дословно – «ИЗ») с указанием имени таблицы, из которой производится выборка.

Далее идет ключевое слово WHERE (дословно с англ. «ГДЕ»), за которым следует часть, определяющая непосредственно условия выборки из таблицы.

После этого идут условия вида «название_поля = значение» разделенные ключевыми словами AND или OR, означающими «И» и «ИЛИ» соответственно.

Таким образом, переводя запрос с SQL на русский мы получим:
ВЫБРАТЬ все поля ИЗ таблицы transactions, ГДЕ поле date = "2015-05-26" И поле user_id = 10
При недостаточной проверке данных от пользователя, злоумышленник может внедрить в форму web-интерфейса приложения специальный код, содержащий кусок запроса к базе данных.  Эта опаснейшая уязвимость, позволит злоумышленнику читать/изменять/удалять информацию, которая для него не предназначена.

Эксплуатация


Как это работает? В рассмотренном примере, значение даты "2015-05-26" попадает в SQL-запрос из URL скрипта, и в целях рассматриваемого примера, никак не фильтруется приложением.

Если передать в параметр date вместе с датой 2015-05-26 еще немного символов:

2015-05-26" AND user_id=11 --

То вместо корректного:

SELECT * FROM transactions WHERE date ="2015-05-26" AND user_id = 10

Указанный запрос сформирует следующий SQL:

SELECT * FROM transactions WHERE date = "2015-05-26" AND user_id = 11 -- " AND user_id = 10 

Два минуса «--» в синтаксисе SQL означают начало комментария, поэтому все символы после «--» интерпретатором восприниматься не будут, и часть запроса, в которой осуществлялась проверка идентификатора пользователя будет отсечена сервером базы данных.

Фактически будет выполнен запрос:

SELECT * FROM transactions WHERE date = "2015-05-26" AND user_id = 11

В результате которого, мы получим информацию о транзакциях другого пользователя. А перебирая id – любого другого пользователя.

Какие бывают техники атак при SQL-инъекциях


Сообществом OWASP были описаны пять основных методов (техник) атак при SQL-инъекциях.

  • Оператор Union: подход может быть использован при наличии уязвимости в запросе SELECT, позволяющей объединить два запроса в один результат или набор результатов.

  • Логический метод: предполагает использование логического условия, либо условий, позволяющих достоверно определить истинность или ложность некоего предположения.

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

  • Метод с альтернативным каналом передачи данных: метод предполагает использование альтернативного канала передачи извлеченных данных (например через исходящее HTTP соединение с web-сервером)

  • Time delay: метод использует команды базы данных, например sleep для того чтобы определить задержу по условным запросам. Метод эффективен, когда нет возможности получить ответ от web-приложения (результат, ошибка)

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

По способу извлечения данных выделяют три типа атак:

  • Связанный: данные в результате инжектированного SQL запроса извлекаются тем же путем, которым был передан сам инжектированный запрос. Это самый прямолинейный вид атаки, в результате которого, запрошенные модифицированным запросом данные, отображаются непосредственно на странице web-приложения.

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

  • Дедуктивный или слепой: В результате SQL инъекции фактического извлечения данных не происходит, но злоумышленник может получить информацию, наблюдая за поведением web-сервера, в результате отправки серии специфических инжектированных SQL запросов.


Как защититься?


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

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

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

Мы приведем некоторый системный подход к реализации защиты от инъекций баз данных. Чтобы свести к минимуму потенциальную угрозу от данного типа атак, нужно последовательно выполнить следующие шаги:

  • Определить все точки получения данных web-приложением извне, выписать все точки входа (URL), названия передаваемых параметров, протокол (HTTP/HTTPS) и метод их передачи – GET, POST, PUT или DELETE.

  • Определить тип данных для каждого параметра, ответив на вопрос — значение какого типа мы должны получить?

  • Реализовать проверку каждого параметра на соответствие типу.

  • Реализовать экранирование кавычек и других спецсимволов при помощи символа обратного слеша “\”. При этом если параметр в запросе заключен в одинарные кавычки, то именно одинарные кавычки должны быть экранированы и заменены на «\’», аналогично с двойными кавычками. При этом экранировать одинарные кавычки внутри двойных не надо и наоборот. Это в теории, на практике же, почти во всех популярных фреймворках и скриптовых языках есть встроенные функции для экранирования спецсимволов, как например mysqli_real_escape_string в php.

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

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

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

Какие еще бывают инъекции?


Помимо инъекций баз данных, атаке типа «инъекция» может быть подвержена любая другая среда, которая получает необработанные данные извне. Еще один распространенный случай – это инъекция командного интерпретатора операционной системы, так называемые «OS injections».

Рассмотрим такой пример из описания «Command injections» OWASP.

Есть некая социальная сеть, предоставляющая пользователям функционал загрузки фотографий и их последующего удаления. В ней есть некий скрипт, написанный на языке PHP, и он отвечает за удаление фотографий:

 <?php
    $file=$_GET['filename'];
    system("rm /var/www/user_photos/$file");
?>

 Типичный его вызов выглядит так:

http://mysocnet.simplethreats.ru/user_file_delete.php?filename=1246.jpg

И влечет за собой исполнение команды:

rm /var/www/user_photos/1246.jpg

Очень легко очистить всю директорию с приложением, передав такой запрос:

user_file_delete.php?filename=../ -rf

(на самом деле пробелы и некие символы закодируются при передаче в URL в нечто вида user_file_delete.php?filename=..%2F+-rf — но для наглядности, мы будем писать с пробелами и другими символами, не заворачивая их)

что вызовет исполнение:

rm /var/www/user_photos/.. –rf

и будет равносильно

rm /var/www/ -rf

то есть удалит (команда rf) все содержимое директории www, где хранятся файлы приложения, без подтверждения (параметр –f) и рекурсивно (параметр -r), т.е. со всеми вложенными директориями и их файлами. Участь — врагу не пожелаешь.

А можно не удалять файловую систему, и передав запрос вида:

user_file_delete.php?filename=12346.jpg && adduser ghost && echo ghostpass | passwd ghost –stdin

Злоумышленник выполнит команду:

rm /var/www/user_photos/12346.jpg && adduser ghost && echo ghostpass | passwd ghost –stdin 


И создаст для себя учетную запись для доступа на сервер.

Нужно отметить, что на практике создать пользователя таким образом почти невозможно, так как Web-сервер в 99% систем запущен от непривилегированного пользователя, который не может создавать другие учетные записи.

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

Первая особенность — это конвейеры (pipelines, pipes, «пайпы»). Суть конвейеров заключается в возможности передачи вывода одной команды на ввод другой, если они разделены оператором «|».

Вторая особенность – возможность запускать комбинацию команд через логические операторы «&&» и «||». Оператор «&&» выполнит следующую указанную команду, в случае если предыдущая исполнена успешно и является неким аналогом логического «И» — выполнить команду один И команду два. Оператор «||» является аналогом логического «ИЛИ» и выполнит вторую команду только в случае если не была выполнена первая — выполнить команду один ИЛИ команду два.

Что дальше?


Разумеется, нами была рассмотрена лишь малая толика того, что можно отнести к разряду инъекций. Огромный пласт занимают так называемые DOM- или HTML-инъекции, благодаря которым становится возможным проведение такого вида атак как XSS.

Проблема XSS во все времена стояла достаточно остро, а сейчас, в эпоху динамичного содержимого, когда JavaScript предоставляет очень мощные возможности, атаки такого рода несут повышенную опасность (вплоть до того, что, зараженное приложение может сфотографировать вас и отправить Ваше фото злоумышленнику).

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

Будьте бдительны!

Немного о SimplePay и авторах
Мы — Иван Притула и Дмитрий Агапитов, занимаемся разработкой решений, которые делают жизнь людей проще и комфортнее. Сегодня мы хотим представить один из наших новых сервисов – это платежный агрегатор SimplePay. Все что мы делаем продиктовано мучительной невозможностью мириться с несовершенством в целом, и несовершенством конкретных программных решений в частности. Именно в погоне за совершенством и рождаются наши продукты.

SimplePay — это современный высокотехнологичный агрегатор платежей. Компания создана в 2014г., зарегистрирована в г. Москве и ведет свою деятельность в соответствии с законодательством Российской Федерации. Наша основная задача, это обеспечение простой, удобной возможности организации приема платежей на интернет-сайтах компаний, вне зависимости от сферы деятельности, масштаба бизнеса и наличия подготовленного технического персонала.

Мы предлагаем следующие услуги:

  • Организацию приема платежей на Вашем сайте
  • Возврат средств покупателю
  • Выставление произвольного счета покупателю
  • Уведомления о платежах как на URL, так и по e-mail
  • Рекуррентные платежи
  • Псевдорекуррентные платежи во всех популярных платежных системах с кошельками

Короткая справка:

  • Банк эквайер: Промсвязьбанк
  • Платежи в пользу третьих лиц: РНКО РИБ
  • Юрисдикция: РФ, 161-ФЗ
  • Работа с нерезидентами: Нет
  • Собственный API: Да
  • Совместимые API: Да
  • CMS-модули: Да
  • Встроенные модули в сторонних системах: BG Billing, WP-shop
  • Переадресация сразу на ПС без промежуточной страницы: Да
  • API на возвраты: Да

Tags:
Hubs:
Total votes 28: ↑17 and ↓11 +6
Views 20K
Comments Comments 15

Information

Founded
Location
Россия
Website
simplepay.pro
Employees
11–30 employees
Registered