Безопасность OpenEdge-приложений
ПОНИМАНИЕ УРОВНЕЙ
Чтобы лучше понять технологию многоуровневой защиты, представьте средневековый замок.
Если хозяин замка мог бы позволить себе большее количество стен и рвов, окружающих внутреннюю область замка, он и его подданные были бы в большей безопасности. Но люди должны иметь возможность покидать замок, например, для работы в поле, следовательно, в стенах должны быть установлены ворота, а по рвам сооружены подъемные мосты. Представим, что уровни защиты, окружающие ваши данные, – это стены, а пути доступа к ним – это ворота. Стены должны быть достаточно прочными, чтобы сопротивляться атакам, а привратники достаточно умными, чтобы обнаружить и преградить доступ вражеским шпионам.
Среда базы данных OpenEdge очень похожа на замок. Стены созданы вокруг данных, чтобы защитить их от несанкционированного доступа, а ворота, установленные в этих стенах, и мосты позволяют авторизованным пользователям свободно взаимодействовать с данными.
Основные уровни защиты OpenEdge:
- Данные
- База данных, содержащая данные
- Среда, окружающая базу данных и пользователей
- Файловая система, содержащая файлы базы данных
- Сервер, содержащий файловую систему
- Сеть, к которой подключен сервер
- Пользователи, у которых есть доступ к сети
ДАННЫЕ
В самом центре замка располагается главный приз – данные. В идеале первый уровень защиты вокруг данных должен быть самым сильным, поскольку он должен не только противостоять атакам извне, но и тем атакам, которые могут возникнуть непосредственно изнутри системы.
По умолчанию OpenEdge обеспечивает безопасность через определенные поля таблиц метасхемы _FILE, _FIELD и _INDEX. Эти поля известны как _CAN*-поля, т.к. их имена имеют вид _CAN-READ, _CAN-WRITE, _CAN-CREATE и т.д. Они существуют с ранних версий Progress[1] и по умолчанию имеют значение «*», что означает – полный доступ для всех. Чтобы это значило? База данных, в которой не были изменены поля безопасности, является открытой на 100% для чтения, записи, создания и удаления любым ABL-клиентом, который смог подключиться к ней. Заметьте, я не говорю об аутентификации, я говорю именно о подключении. Существование и/или использование имен пользователей и паролей не является достаточным, когда заданные по умолчанию параметры безопасности оставляют неизменными. С такими параметрами буквально все запросы на установление соединения с базой данных удовлетворяются, и у всех таких подключенных процессов есть беспрепятственный доступ к данным.
Управление доступом происходит иначе, когда к базе выполняется SQL-подключение. Начиная с версий Progress 9, в СУБД было добавлено родное ядро SQL, а вместе с ним и более совершенная SQL-защита. В SQL-модели наличие пользователей является обязательным, а объекты базы данных по умолчанию принадлежат тому пользователю, который их создал. Другими словами, только создатель объекта базы данных может читать, изменять, создавать или удалять данные в пределах объекта. Любой другой пользователь для обращения к данным должен получить соответствующий доступ, который может предоставить (GRANT) владелец объекта или администратор базы данных.
Сравнивая эти две модели защиты, довольно ясно можно понять – они полностью противоположны друг другу. Модель защиты OpenEdge по умолчанию – это «GRANT * TO * (PUBLIC)», т.е. всем пользователям по умолчанию предоставлены все привилегии. В терминах SQL заданная по умолчанию безопасность OpenEdge эквивалентна выполнению команды «GRANT ALL ON object TO PUBLIC» для каждого объекта в базе. С другой стороны, модель SQL – это «GRANT Ø TO Ø (NOBODY)», т.е. по умолчанию ни у кого нет никаких привилегий.
Когда дело доходит до управления SQL- и OpenEdge- безопасностью, задачи администратора базы данных, так же как и модели защиты, противоположны. На стороне OpenEdge доступ установлен в «PUBLIC», поэтому администратор базы данных должен изменить _CAN*-поля, чтобы ограничить возможности пользователей. Это достигается путем замены знака «*» (PUBLIC) на конкретные ID пользователей и/или маски. Например, «FIN*» означает, что всем пользователям, имена которых начинаются на «FIN», предоставлены привилегии _CAN*. Кроме того, доступ может быть запрещен знаком «!», если он один, это означает, что «пустому пользователю» (Blank User ID) доступ запрещен, если он имеет дополнительные символы или выражения (маску), например, «!FIN*», то это означает, что всем пользователям, имена которых начинаются с «FIN», привилегии _CAN* запрещены. В SQL мы явно выполняем оператор GRANT в следующем виде «GRANT privilege ON object TO user-id». Например, команда «GRANT SELECT ON PUB.CUSTOMER TO KOUP» разрешает пользователю, аутентифицированному как KOUP, выбирать данные из таблицы CUSTOMER в схеме PUB.
Другой очень важный факт относительно безопасности OpenEdge заключается в том, что до 10.1A _CAN*-ограничения применялись только в момент компиляции. Например, пользователь, компилирующий программу, которая изменяет таблицу CUSTOMER, должен иметь права на _CAN-WRITE, чтобы получить доступ к этой таблице. Однако, как только r-код сгенерирован, любой пользователь может использовать его, чтобы успешно изменить таблицу CUSTOMER – _CAN*-поля полностью игнорируются. Для примера представим себе разработчика, у которого обычно нет доступа к промышленной базе данных. Если он попытается выполнить запросы к этой базе, то настройки _CAN*-полей будут препятствовать ему, а его запросы не будут компилироваться. Однако тот же самый разработчик может скомпилировать свой запрос на идентичной базе данных разработки, к которой у него, по-видимому, есть полный доступ, и сгенерировать r-код, чтобы затем успешно выполнить его на промышленной базе данных.
Чтобы нейтрализовать эту брешь в защите, специалисты Progress разработали функцию DBAUTHKEY, которая внедряет уникальный идентификатор базы данных в r-код, и это позволяет выполнить его только на конкретной базе данных. Другими словами, r-код, откомпилированный на базе данных разработки, не будет выполнен при подключении к промышленной базе данных. К сожалению, профессиональные хакеры нашли способ обойти безопасность DBAUTHKEY (как и в случае других функций защиты данных). Сегодня функция DBAUTHKEY подобна сигналу тревоги на вашем автомобиле – достаточное средство устрашения против бесхитростных атак, но бесполезное против интеллектуального и решительного противника. Тем не менее, есть смысл в использовании функции DBAUTHKEY, она чрезвычайно проста в реализации, но в то же время её сравнительно сложно обойти. В сочетании с другими решениями, предлагаемыми в статье, эта функция уменьшает вероятность взлома вашей базы данных.
Реальное решение проблемы «_CAN*» было реализовано в OpenEdge 10.1A. У администратора базы данных появилась возможность с помощью опции «Enable run-time security» установить проверку прав доступа во время выполнения r-кода. Если эта опция включена, то каждая ABL-попытка доступа к базе данных будет проверяться независимо от источника запроса (в данном случае – r-код или динамически сгенерированный запрос).
Теперь у администратора базы данных есть возможность проверить достоверность доступа во время выполнения. Остается определить, какие пользователи должны иметь доступ к тем или иным таблицам. Легко сказать: «Пользователь X имеет доступ к записям о коммерческих заказах». Труднее экстраполировать этот функционал доступа к базе данных. Какие таблицы и поля требуются для доступа к коммерческим заказам? Их необходимо только читать, или заказы разрешено изменять, создавать и удалять? Что если изменение записи о коммерческих заказах вызывает другие программы, отвечающие за обновление запасов, поставок, заказов на выполнение работ или на планирование? Возможно, что пользователю также должен быть предоставлен доступ к таблицам в базе данных, связанным с этими действиями, но только в пределах строгих границ заказа. Другими словами, пользователь может изменить имеющийся уровень запасов, подтверждая заказ, но не может войти в блок «Обслуживание Запасов» и вручную управлять уровнями запасов.
Остановитесь и задумайтесь: мы почти завершили полный цикл! Первоначально безопасностью управляли только через приложение. Этого, как оценивалось, было недостаточно из-за многих способов, которые использовались для обращения к данным вне границ приложения. В результате, чтобы управлять доступом к данным независимо от источника, была реализована безопасность во время выполнения. Однако в приложении может потребоваться более либеральный доступ пользователя к данным для поддержания функциональных требований. Приложение может требовать, чтобы к определенным объектам был предоставлен косвенный доступ, тогда как прямой доступ к тем же объектам должен быть запрещен! Как это сделать? Мы предоставим доступ на этот уровень безопасности и более надежно защитим внешние уровни, ограничив каналы, через которые пользователь может обратиться к данным! Прежде чем я начну рассказывать, как это сделать, мы должны изучить следующий уровень защиты, реализованный в самой СУБД[2].
[1] Автор пытался найти точную версию, в которой эти поля были введены, но, похоже, что за двадцать с лишним лет эта информация была безвозвратно утрачена.
Метка:OpenEdge, OpenEdge Security