Планирование и автоматизация проверок безопасности баз данных упрощает тестирование

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

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

 

Автоматическое тестирование

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

Например, выполнив код T-SQL, показанный в листинге 1 (вставив собственный номер версии), можно выяснить, установлен ли на сервере базы данных последний пакет обновлений. А чтобы определить, была ли отключена ненужная служба, можно выполнить код из листинга 2, который проверяет, работает или нет служба координатора распределенных транзакций (MSDTC).

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

  • Четко определенный план каждой проверки, включающий ожидаемый результат (например, все версии SQL Server равны или превышают номер 8.00.2039), чтобы можно было определить, правильно ли установлен параметр, и условия проведения теста (сервер работает, база данных поддерживает все тестируемые настройки, тест имеет необходимые разрешения и для сценария, и в местах проверки).
  • Составление отчетов о результатах каждой проверки.
  • Отдельный отчет о недостатках, который создается, когда значение параметра нарушает политику безопасности.

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

 

Ведение журнала отчетов о проверках

Запись отчета о тесте должна быть частью процедуры тестирования; она производится при каждой проверке той или иной настройки безопасности. Каждый отчет должен содержать как минимум уникальный идентификационный номер (ID), дату проверки, имя выполнявшего проверку сотрудника, ожидаемое и актуальное значение проверяемого параметра и, наконец, резюме теста — успешный или неуспешный. Далее я поясню, как определить ожидаемое значение теста.

Можно создать таблицу и хранить в ней результаты отчетов, генерируемые в процессе тестов конфигурации, как показано в коде T-SQL листинга 3. Два отчета, приведенные в табл. 1, содержат примеры результатов тестов, подобные результатам, которые можно увидеть, выполняя предыдущие сценарии тестов. Позже я расскажу об особой технике написания сценариев для перемещения результатов тестов в таблицу, а также для автоматизации других частей процесса тестирования.

Вести журналы необходимо — это экономит время, обеспечивает целостность данных и сокращает дублирование тестов. Разработчики могут использовать эти результаты для воспроизведения очевидных ошибок. Тестировщики могут применять их для проверки сделанных корректировок. Ведение журнала проверок избавит администратора от проведения незапланированных и недокументированных тестов. Тем более что автоматизировать ведение журнала отчетов о проверках так же просто, как сами проверки безопасности.

Следует также вести журнал ошибок с записями обо всех обнаруженных нарушениях и потенциальных уязвимых местах системы безопасности. Отчет об ошибках должен содержать ту же информацию, что и отчет о проверке, плюс уникальный номер ошибки, дата составления отчета, описание проблемы и состояние работы над ошибкой (например, «тестируется», «отладка», «уточнение», «устранена»). Некоторые компании, возможно, сочтут необходимым добавить к этому перечню еще один пункт — указание на соответствующее требование политики безопасности.

Чтобы вести журнал ошибок, сначала нужно создать другую таблицу, соответствующую данным отчета об ошибках, но на этот раз используя код, подобный коду листинга 4. Чтобы представить, как выглядит отчет об ошибках, рассмотрим такой пример: проверка безопасности показала, что сервер работает под учетной записью LocalSystem (что категорически запрещается почти на любом производстве, см. код листинга 5). Отчет об ошибке по этой проверке может выглядеть примерно так, как показано в табл. 2. Обратите внимание на столбец Current Status, где состояние «отладка» (Debugging) означает, что тестирование приостановлено до окончательного решения проблемы. Как только проблема будет устранена, администратор или разработчик переустанавливает состояние в значение «тестируется» (дефектная настройка — LocalSystem в данном случае — обнаружена и приведена в порядок) или в состояние «закрыто» (проблема решена по-другому).

 

Выбор эталона

Чтобы уметь определять ожидаемый результат теста, нужно иметь эталон настроек безопасности. Конфигурацию системы безопасности можно сверять с различными эталонами — например, совокупностью бизнес-правил или такими требованиями, как «SQL Server должен быть установлен на выделенном сервере», с правилами для проектировщиков типа «каждая процедура ввода должна содержать подпрограмму проверки данных», с рекомендациями производителей, такими как Security Best Practices (SBP) Checklist от Microsoft, а также с национальными стандартами безопасности для промышленных предприятий.

В этой статье в качестве эталона для проверок безопасности я использую SBP Checklist от Microsoft. Если у организации еще нет собственного плана обеспечения безопасности баз данных или выработанных рекомендаций по мерам безопасности, я предлагаю использовать SBP Checklist в качестве руководства для их разработки. По мере изменения потребностей всегда можно добавить новые или пересмотреть существующие политики безопасности. Перечень рекомендаций можно найти в SQL Server 2000 SP3 Security Features, а подробное описание модели безопасности — на http://www.microsoft.com/technet/prodtechnol/sql/2000/maintain/sp3sec00.mspx. Таблица 3 содержит некоторые примеры из перечня лучших методов Microsoft Security Best Practices Checklist.

 

Другие приемы автоматизации

Я показал несколько образцов кода для автоматизации отдельных сторон тестирования системы безопасности: выполнения теста конфигурации и создания таблиц для хранения отчета с результатами теста и отчета об ошибках. Можно написать код для автоматизации других действий, например создания отчета и ведения журнала ошибок.

Как автоматизировать создание отчета о тесте? Мы уже имели дело с примером кода, который создает пустую таблицу для отчетов, tabConfigSettings. Теперь нам нужен код, который перемещает в нее результаты тестов. Для этого можно использовать простой оператор INSERT, как показано ниже, который помещает результаты теста на наличие последней версии пакета обновлений в таблицу tabConfigSettings:

INSERT tabConfigSettings
(ConfigItem, ExpectedSetting)
VALUES
(‘Version#’, ‘8.00.2039’)

Значение Version# должно соответствовать конкретной конфигурации.

Можно сделать еще лучше — не создавать оператор INSERT для каждого набора отдельно, а использовать хранимую процедуру, такую как показана в листинге 6, которая автоматизирует задачу перемещения в таблицу для всех результатов тестов.

Теперь нам нужен способ автоматического ведения журнала результатов тестов. Для этого можно использовать оператор UPDATE, примерно так, как это сделано в листинге 7. Поскольку каждая настройка безопасности повторяет ту же базовую логику, что и этот оператор UPDATE, можно просто вставить оператор внутрь другой хранимой процедуры, как в процедуре upUpdateTestCase в листинге 8. Процедура upUpdateTestCase принимает три входных значения: название элемента конфигурации, результат проверки и актуальная настройка элемента конфигурации.

Применяя технику написания сценариев, аналогичную только что описанной, можно автоматизировать создание отчетов об ошибках. Основной способ решения этой задачи — использовать оператор INSERT, как в листинге 9, который назначает каждому отчету об ошибке уникальный идентификационный номер (TestID), указывает на тестируемый конфигурационный параметр и другую важную информацию. Другой способ состоит в написании отдельной процедуры, которая записывает отчет по окончании теста, в зависимости от результата теста. Ошибка фиксируется, только если параметр не прошел проверку. Имеется также возможность фиксировать отчеты об ошибках вручную или с использованием другого средства тестирования. Для таких случаев создается триггер к таблице tabConfigSettings, который автоматически генерирует отчеты об ошибках. Как показано в листинге 10, триггер trgLogBug запускается каждый раз, когда происходит обновление таблицы tabConfigSettings. Сначала trgLogBug проверяет, какое значение указано в столбце результата теста (который автоматически создается триггером во временной таблице). Если значение Fail (неуспешный) отсутствует, т. е. тест пройден, никакого отчета об ошибке не генерируется. Если в столбце результата теста стоит Fail, триггер trgLogBug вставляет в таблицу tabBugReports новый отчет об ошибке, беря нужные записи из обновленной таблицы tabConfigSettings.

 

От элементов автоматизации к автоматизированной системе

Итак, мы рассмотрели основные части автоматизированной системы контроля состояния системы безопасности. Осталась только одна проблема. Хотя отдельные шаги автоматизированы, процесс в целом все еще требует ручного вмешательства. Это можно исправить, написав код, который инициирует каждый шаг автоматически. Для этого сначала нужно упаковать каждый шаг в другую хранимую процедуру, как показано в листинге 11. Процедура upVerifySecurityConfiguration (см. листинг 12) вставляет части теста в таблицу tabConfigSettings, затем проверяет корректность каждой настройки безопасности. Обратите внимание, что процедура upVerifySecurityConfiguration содержит две предыдущие процедуры, upInsertTestCase и upUpdateTestCase.

Если требуется расширить upVerifySecurityConfiguration, следует просто включить в нее дополнительные тесты с соответствующими макропрограммами автоматизации. Таблица 4 содержит дополнительные сценарии автоматизированной проверки безопасности, которые также можно использовать. Как и три первые теста, каждый из этих сценариев предназначен для проверки настроек безопасности из списка Microsoft SBP Checklist. В табл. 4 также показаны цель теста и ожидаемое значение параметра для SBP-совместимых серверов и баз данных. Просто пополняйте собственный процесс автоматизированных проверок безопасности необходимыми макропрограммами.

Теперь осталось написать код для автоматизации создания отчетов и ведения журнала ошибок. Все относящееся к отчетам обеспечивается таблицей tabConfigSettings и триггером trgLogBug. Для того чтобы все заинтересованные лица могли быть в курсе результатов последних тестов, можно просто опубликовать эти таблицы, пользуясь инструментом SQL Server для работы с отчетами в Web под названием sp_makewebtask (см. код листинга 13).

Вид таблицы tabConfigSettings после выполнения всех 15 конфигурационных тестов базы данных SQL Server Northwind (с настройками по умолчанию при стандартной установке SQL Server 2000 на ноутбуке Toshiba, работающем под Windows XP) показан в табл. 5. Как можно заметить, 9 из 15 тестов обнажают настройки безопасности, нарушающие собственные рекомендации Microsoft (SBP).

 

Дальнейшие шаги

В каждой организации, конечно, требуется конкретизировать примеры кода, которые приведены в этой статье, включив в них проверки безопасности, необходимые для создания собственной автоматизированной модели. Следует разработать набор проверок, выполняемых через сценарии, которые отвечают необходимым условиям безопасности, и оценить проверяемые пункты с точки зрения конкретной модели безопасности. Есть ли в организации хотя бы один тест для каждой политики безопасности, входящей в модель? Если нет, требуется его разработать. Кроме того, важно оценить, насколько хороши сами политики безопасности. Соответствует ли модель безопасности организации каждому пункту рекомендаций Microsoft SBP Checklist? Если нет, нужно установить причину несоответствия.

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

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

Дэн Сойер - консультант и инструктор по проектированию и реализации баз данных и процедур тестирования. (mailto:http://www.dansawyer.net)


Листинг 1
DECLARE @ProductVersion varchar(32) SELECT @ProductVersion = cast(SERVERPROPERTY   (‘ProductVersion’) as varchar(32)) IF @ProductVersion >= ‘8.00.2039’  PRINT ‘PASS’

Листинг 2
DECLARE @MSDTC INT EXECUTE master..xp_instance_regread  N’HKEY_LOCAL_MACHINE’,  N’SYSTEMCurrentControlSetServicesMSDTC’,    N’Start’,@MSDTC OUTPUT  IF @MSDTC = 3  PRINT ‘PASS’ /* Note: 3 = Disabled */

Листинг 3
CREATE TABLE tabConfigSettings (SettingID int IDENTITY (1,1),  ConfigItem varchar(32), ExpectedSetting varchar(64),  ActualSetting varchar(64), TestResult char(10),  Tester varchar(32)   DEFAULT CURRENT_USER, TestDate datetime    DEFAULT getdate() )

Листинг 4
CREATE TABLE tabBugReports (BugID int IDENTITY(1,1),  TestID int, ConfigItem varchar(32),  DateLogged datetime, ExpectedSetting varchar(64),  ActualSetting varchar(64), Tester varchar(32),  Status varchar(32) )

Листинг 5
DECLARE @LocalSystem nvarchar(200)  EXEC master.dbo.xp_regread   ‘HKEY_LOCAL_MACHINE’ , ‘SYSTEMCurrentControlSet    ServicesMSSQLSERVER’, ‘ObjectName’, @LocalSystem OUTPUT  IF @LocalSystem =   ‘LocalSystem’ PRINT ‘FAIL’

Листинг 6
CREATE PROC upInsertTestCase   @@ConfigItem varchar(32),   @@ExpectedSetting varchar(64) AS SET NOCOUNT ON   — Введите тестовые данные в таблицу tabConfigSettings   INSERT tabConfigSettings (ConfigItem, ExpectedSetting)   VALUES (@@ConfigItem, @@ExpectedSetting)   RETURN

Листинг 7
IF @ProductVersion >= ‘8.00.2039’    BEGIN    UPDATE tabConfigSettings    SET ActualSetting = @ProductVersion,       TestResult = ‘PASS’,       Tester = CURRENT_USER,       TestDate = getdate()    WHERE ConfigItem = ‘Version#’ END ELSE    BEGIN    UPDATE tabConfigSettings    SET ActualSetting = @ProductVersion,       TestResult = ‘FAIL’,       Tester = CURRENT_USER,       TestDate = getdate()    WHERE ConfigItem = ‘Version#’ END

Листинг 8
CREATE PROC upUpdateTestCase       @@TestResult varchar(10),       @@ActualSetting varchar(64),       @@ConfigItem varchar(64) AS SET NOCOUNT ON    IF @@TestResult = ‘FAILED’    BEGIN       UPDATE tabConfigSettings        SET ActualSetting = @@ActualSetting,       TestResult = ‘FAIL’,       Tester = CURRENT_USER,       TestDate =  getdate()    WHERE ConfigItem = @@ConfigItem    END    ELSE    BEGIN       UPDATE tabConfigSettings       SET ActualSetting = @@ActualSetting,       TestResult = ‘PASS’,       Tester = CURRENT_USER,       TestDate =  getdate()    WHERE ConfigItem = @@ConfigItem    END RETURN

Листинг 9
INSERT tabBugReports (TestID, ConfigItem, DateLogged,    ExpectedSetting, ActualSetting, Tester, Status) VALUES ([yourtestid], [yourconfigitem],  getdate(), [yourexpectedsetting],    [youractualsetting], ‘dbo’, ‘Debugging’ )

Листинг 10
CREATE TRIGGER trgLogBug ON tabConfigSettings FOR update AS IF (select testresult from deleted) = ‘FAIL’    BEGIN    DECLARE @TestID INT, @ConfigItem varchar(32),       @ExpectedSetting varchar(64),       @ActualSetting varchar(64), @Tester varchar(32)    SELECT @TestID = SettingID,       @ConfigItem = ConfigItem,       @ExpectedSetting = ExpectedSetting,       @ActualSetting = ActualSetting,       @Tester =Tester    FROM inserted    INSERT tabBugReports (TestID, ConfigItem, DateLogged,       ExpectedSetting, ActualSetting,Tester, Status)    VALUES (@TestID,@ConfigItem, getdate(),@ExpectedSetting,       @ActualSetting, @Tester, ‘Debugging’) END RETURN

Листинг 11
IF @ProductVersion >= ‘8.00.2039’   BEGIN    UPDATE tabConfigSettings    SET ActualSetting = @ProductVersion,      TestResult = ‘PASS’,      Tester = CURRENT_USER,      TestDate = getdate()    WHERE ConfigItem = ‘Version#’    END   ELSE    BEGIN    UPDATE tabConfigSettings    SET ActualSetting = @ProductVersion,        TestResult = ‘FAIL’,        Tester = CURRENT_USER,        TestDate = getdate()    WHERE ConfigItem = ‘Version#’    END

Листинг 12
CREATE PROCEDURE upVerifySecurityConfiguration AS   SET NOCOUNT ON /* Шаг 1: задаем наборы тестовых данных */ EXEC upInsertTestCase   @@ConfigItem = ‘ServiceAccount’,   @@ExpectedSetting = ‘NT_ACCOUNT’  /* ...другие наборы тестовых данных... */  /* Шаг 2: начинаем проверки */ DECLARE @LocalSystem nvarchar(200) EXEC master..xp_regread ‘HKEY_LOCAL_MACHINE’,   ‘SYSTEMCurrentControlSetServicesMSSQLSERVER’,   ‘ObjectName’, @LocalSystem OUTPUT   IF @LocalSystem = ‘LocalSystem’ EXEC upUpdateTestCase    @@TestResult = ‘FAILED’,    @@ActualSetting = ‘LocalSystem’,    @@ConfigItem = ‘ServiceAccount’   ELSE   EXEC upUpdateTestCase    @@TestResult = ‘PASSED’,    @@ActualSetting = ‘@LocalSystem’,    @@ConfigItem = ‘ServiceAccount’  /* ...другие проверки... */ 	RETURN

Листинг 13
Exec sp_makewebtask    @outputfile = ‘c:SecurityChecks.htm’,    @resultstitle = ‘Security Test Results’,    @query = ‘SELECT  *     FROM tabConfigSettings    ORDER BY  TestResult, TestDate’ and Exec sp_makewebtask    @outputfile = ‘c:SecurityBugReport.htm’,    @resultstitle = ‘Security Bugs’,    @query = ‘SELECT  *    FROM tabBugReports    ORDER BY  DateLogged’

Таблица 1. Таблица 2. Таблица 3. Таблица 4. Таблица 5.