Недавно мне задали следующий вопрос: «Можно ли получить данные для регистрации или защищенные данные из резервной копии базы данных 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.
Экран 2. Результаты с именем входа только с разрешениями роли db_creator |
Похоже, мы видим результаты из запроса к системной таблице sys.server_prinicpals в восстановленной копии master из другого экземпляра SQL Server. Здесь что-то не так. Вы видите ошибку? Имя регистрации NotIt не существовало на другом экземпляре, из которого получена резервная копия master. Мне стало любопытно, и я повторно запустил тот же запрос, выполнив регистрацию во второй экземпляр с разрешениями sysadmin, обеспечивающими доступ ко всем метаданным, размещенным в любой пользовательской и системной базе данных. Полученные результаты показаны на экране 3.
Экран 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;
Экран 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;
Экран 5. Пользовательские объекты, видимые для db_owner |
Хотя имя регистрации является владельцем базы данных, ему не предоставлены неявные разрешения для пользовательских таблиц (см. экран 6). Однако это не мешает имени регистрации, имеющему право предоставить разрешения, сделать так на новом экземпляре. Если пользователь, который восстановил копию master на новом экземпляре, имеет соответствующие права, он увидит все созданные пользователями объекты, как и в несистемной базе данных.
Экран 6. Ответ на запрос с учетными данными владельца для базы данных copy_of_master |
Таким образом, ответ на вопрос, поставленный в начале статьи, отрицательный. Хотя вы можете восстановить копию master и направлять к ней запросы, вы не только не можете увидеть полную информацию для регистрации, поскольку это системное представление, полученное из базы данных resource текущего экземпляра, но вам также не удастся увидеть созданные пользователем объекты и направлять к ним запросы. До тех пор пока вы не получите соответствующих полномочий обычными средствами на новом экземпляре от имени учетной записи с соответствующими правами.
Необходимо всегда принимать меры для надежной защиты всех резервных копий своих баз данных, поскольку, как было показано выше, каждый, кто может обратиться к вашим базам данных, может восстановить их в другом месте и в конечном итоге получить доступ к содержащимся в них секретам, если имеет соответствующие права.
--РЕЗЕРВНОЕ КОПИРОВАНИЕ БАЗЫ ДАННЫХ 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;
--ВОССТАНОВИТЬ КАК КОПИЮ БАЗЫ ДАННЫХ 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;
--ПОДТВЕРЖДЕНИЕ ВОССТАНОВЛЕНИЯ КАК НЕПРИВИЛЕГИРОВАННОЙ УЧЕТНОЙ ЗАПИСИ /* Владение только восстановленной копией 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’;
--МОЖНО ЛИ ЗАПРОСИТЬ СВЕДЕНИЯ ДЛЯ РЕГИСТРАЦИИ В КОПИИ? 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;