Недавно мне задали следующий вопрос: «Можно ли получить данные для регистрации или защищенные данные из резервной копии базы данных master?» Я всегда в поиске интересных тем для своих статей, поэтому решил ответить на этот вопрос на страницах журнала.

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

В листинге 1 показан процесс резервного копирования базы данных master пользователя с соответствующими правами администратора.

Я пройду по процессу восстановления из резервной копии master. Это позволит создать пользовательскую базу данных с именем copy_of_master. Чтобы выявить уязвимые места в случаях, когда недостаточно надежно защищено местонахождение файлов резервной копии или данные и резервные копии находятся в неактивном состоянии, я восстановлю эту резервную копию на другом экземпляре SQL Server с использованием имени регистрации SQL, не имеющего прав на экземпляре, из которого происходит резервная копия master (см. листинг 2).

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

 

Владелец восстановленной базы данных
Экран 1. Владелец восстановленной базы данных

 

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

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

Напомню, первоначальный вопрос был следующий: можно ли восстановить копию master, а затем запросить сведения для регистрации? Первая задача решается с помощью запроса, представленного в листинге 4.

На данном этапе я выполняю этот запрос с именем входа NotIt с низкими привилегиями. С учетом этого обстоятельства посмотрим на результаты запроса, представленные на экране 2.

 

Результаты с именем входа только с разрешениями роли db_creator
Экран 2. Результаты с именем входа только с разрешениями роли db_creator

 

Похоже, мы видим результаты из запроса к системной таблице sys.server_prinicpals в восстановленной копии master из другого экземпляра SQL Server. Здесь что-то не так. Вы видите ошибку? Имя регистрации NotIt не существовало на другом экземпляре, из которого получена резервная копия master. Мне стало любопытно, и я повторно запустил тот же запрос, выполнив регистрацию во второй экземпляр с разрешениями sysadmin, обеспечивающими доступ ко всем метаданным, размещенным в любой пользовательской и системной базе данных. Полученные результаты показаны на экране 3.

 

Результаты с именем входа с разрешениями роли sysadmin
Экран 3. Результаты с именем входа с разрешениями роли sysadmin

 

Интересно, не правда ли? Имя регистрации NotIt владеет восстановленной копией базы данных master и поэтому должно иметь возможность доступа ко всем данным, сохраненным в базе данных. Однако явно что-то не так, поскольку возвращенные результаты не только не показывают всех результатов, сохраненных в базе данных, но и включают в себя имя регистрации NotIt, не существующее в экземпляре, из которого извлечена резервная копия базы данных master.

Такая ситуация существует начиная с 2005 года. Это было время, когда база данных master перестала быть источником большинства метаданных экземпляра, и в этом качестве ее заменила база данных resource, которую могут напрямую запрашивать конечные пользователи, даже не участники роли sysadmin. Результаты сходны с ныне свойственными базе данных master: то, что выглядит как системные таблицы, в действительности является представлениями, получаемыми из базы данных resource. Это означает, что, хотя база данных master восстановлена с другого экземпляра, направляя запросы к указанным выше «таблицам» — sys.databases, sys.server_principals, sys.server_role_members, вы на самом деле обращаетесь к системным представлениям, получаемым из базы данных resource текущего экземпляра. Поэтому вы видите только результаты, соответствующие вашим правам, в данном случае всегда существующей учетной записи sa и текущему имени регистрации NotIt. Это объясняет и существование имени регистрации, которое отсутствовало в исходном экземпляре, а также причины, по которым более привилегированная учетная запись видит больше результатов того же запроса.

«Другие» данные в базе данных master

Известен порядок работы в случае, когда любые или все метаданные получены из базы данных resource. Но как быть с нарушениями оптимальных методик, когда администраторы баз данных создают объекты в базе данных master, такие как пользовательские таблицы и хранимые процедуры?

Прежде чем сделать резервную копию базы данных master, я создал несколько таблиц для базы данных для униформы оркестра, в котором участвует мой сын. Я построил эту базу данных просто из интереса. Рассмотрим приведенный на экране 4 список, полученный при работе с исходной базой данных master в качестве sysadmin:

SELECT name, type
FROM master.sys.objects
WHERE type = 'U'
ORDER BY name;

 

Пользовательские объекты в исходной базе данных master
Экран 4. Пользовательские объекты в исходной базе данных master

 

Обратите внимание, что некоторые таблицы создаются системой, но классифицируются как пользовательские таблицы (спасибо Microsoft за путаницу). Как бы то ни было, поскольку все они классифицируются как созданные пользователем таблицы в восстановленной базе данных и имя регистрации NotIt является владельцем восстановленной базы данных master (как copy_of_master), мы должны увидеть те же самые объекты, когда направляем запрос к восстановленной копии как пользователь NotIt, не так ли? Выполним тот же запрос, который показан выше, но применительно к базе данных copy_of_master на новом экземпляре:

SELECT name, type
FROM copy_of_master.sys.objects
WHERE type = 'U'
ORDER BY name;

Хотя мы выполнили этот запрос с учетными данными владельца для базы данных copy_of_master, мы не можем увидеть объекты, созданные пользователями, в базе данных master на исходном экземпляре SQL Server — только системные таблицы, замаскированные под созданные пользователями (см. экран 5). Можно ли запросить таблицы напрямую?

SELECT * FROM copy_of_master.dbo.Coats;

 

Пользовательские объекты, видимые для db_owner
Экран 5. Пользовательские объекты, видимые для db_owner

 

Хотя имя регистрации является владельцем базы данных, ему не предоставлены неявные разрешения для пользовательских таблиц (см. экран 6). Однако это не мешает имени регистрации, имеющему право предоставить разрешения, сделать так на новом экземпляре. Если пользователь, который восстановил копию master на новом экземпляре, имеет соответствующие права, он увидит все созданные пользователями объекты, как и в несистемной базе данных.

 

Ответ на запрос с учетными данными владельца для базы данных copy_of_master
Экран 6. Ответ на запрос с учетными данными владельца для базы данных copy_of_master

 

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

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

Листинг 1. Резервное копирование базы данных master
--РЕЗЕРВНОЕ КОПИРОВАНИЕ БАЗЫ ДАННЫХ MASTER
BACKUP DATABASE [master]
TO  DISK = N'C:\Data\MSSQL12.MSSQLSERVER\MSSQL\Backup\master_foo.bak'
WITH
        COPY_ONLY,
        NAME = N'full master backup copy-only',
        COMPRESSION,
        STATS = 100;
Листинг 2. Восстановление базы данных master
--ВОССТАНОВИТЬ КАК КОПИЮ БАЗЫ ДАННЫХ MASTER
USE [master]
RESTORE DATABASE [copy_of_master]
FROM  DISK = N'C:\Data\MSSQL12.MSSQLSERVER\MSSQL\Backup\master_foo.bak'
WITH 
        FILE = 1, 
        MOVE N'master' TO N'C:\Data\MSSQL12.MSSQLSERVER\MSSQL\DATA\copy_of_master.mdf', 
        MOVE N'mastlog' TO N'C:\Data\MSSQL12.MSSQLSERVER\MSSQL\DATA\copy_of_master.ldf', 
        --NOUNLOAD, 
        STATS = 100;
GO
--МОЖНО ЛИ НАПРАВИТЬ ЗАПРОС ОБ ИМЕНИ ВХОДА В КОПИИ?
SELECT name
         , sid
         , type
         , type_desc
         , is_disabled
         , default_database_name
FROM copy_of_master.sys.server_principals
WHERE type_desc != 'CERTIFICATE_MAPPED_LOGIN'
ORDER BY type_desc;
Листинг 3. Определение владельца восстановленной базы данных
--ПОДТВЕРЖДЕНИЕ ВОССТАНОВЛЕНИЯ КАК НЕПРИВИЛЕГИРОВАННОЙ УЧЕТНОЙ ЗАПИСИ
/* Владение только восстановленной копией master*/

SELECT DB.name,
        SP.name AS owner_name
FROM sys.databases AS DB
        INNER JOIN sys.server_principals AS SP
                ON DB.owner_sid = SP.sid
ORDER BY DB.name;

--КАКИЕ ПРАВА ВОССТАНАВЛИВАЕМОЕ ИМЯ ВХОДА ИМЕЛО НА ЭКЗЕМПЛЯРЕ?
/* Может видеть только восстановленную базу данных, которой владеет, системные базы данных, и базу данных по умолчанию имени входа.*/
SELECT name
         , default_database_name
FROM copy_of_master.sys.server_principals
WHERE type_desc NOT IN ('CERTIFICATE_MAPPED_LOGIN', 'SERVER_ROLE')
ORDER BY name;

/* Только участие в роли сервера db_creator, чтобы обеспечить возможность восстановления*/
SELECT LOGINS.name AS login_name,
        ROLES.name AS role_name
FROM sys.server_principals AS LOGINS
        INNER JOIN sys.server_role_members AS ROLE_MEMBERSHIP
                ON LOGINS.principal_id = ROLE_MEMBERSHIP.member_principal_id
        INNER JOIN sys.server_principals AS ROLES
                ON ROLE_MEMBERSHIP.role_principal_id = ROLES.principal_id
WHERE LOGINS.name = ‘NotIt’;
Листинг 4. Запрос сведений для регистрации
--МОЖНО ЛИ ЗАПРОСИТЬ СВЕДЕНИЯ ДЛЯ РЕГИСТРАЦИИ В КОПИИ?
SELECT name,
         type,
         type_desc,
         is_disabled,
         default_database_name
FROM copy_of_master.sys.server_principals
WHERE type_desc NOT IN ('CERTIFICATE_MAPPED_LOGIN', 'SERVER_ROLE')
ORDER BY type_desc;