SQL Server: как разрешить схемы? - PullRequest
       22

SQL Server: как разрешить схемы?

25 голосов
/ 06 февраля 2010

Вдохновленный различными вопросами, связанными со схемой, которые я видел ...

Цепочка владения позволяет мне предоставить GRANT EXECUTE для хранимой процедуры без явных разрешений для таблиц, которые я использую, если хранимая процедура и таблицы находятся в одной схеме.

Если мы будем использовать отдельные схемы, то мне придется явно GRANT XXX для таблиц с различными схемами. Пример цепочки владения демонстрирует это. Это означает, что пользователь, выполняющий хранимую процедуру, может читать / записывать ваши таблицы напрямую.

Это все равно, что иметь прямой доступ к переменным вашего экземпляра в классе, минуя getter / setters, нарушая инкапсуляцию.

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

Итак, как мы можем поддерживать разделение схем и предотвращать прямой доступ к таблицам?

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

Редактировать, пример

CREATE USER OwnsMultiSchema WITHOUT LOGIN
GO
CREATE SCHEMA MultiSchema1 AUTHORIZATION OwnsMultiSchema
GO
CREATE SCHEMA MultiSchema2 AUTHORIZATION OwnsMultiSchema
GO

CREATE USER OwnsOtherSchema WITHOUT LOGIN
GO
CREATE SCHEMA OtherSchema AUTHORIZATION OwnsOtherSchema
GO

CREATE TABLE MultiSchema1.T1 (foo int)
GO
CREATE TABLE MultiSchema2.T2 (foo int)
GO
CREATE TABLE OtherSchema.TA (foo int)
GO

CREATE PROC MultiSchema1.P1
AS
SELECT * FROM MultiSchema1.T1
SELECT * FROM MultiSchema2.T2
SELECT * FROM OtherSchema.TA
Go
EXEC AS USER = 'OwnsMultiSchema'
GO
--gives error on OtherSchema
EXEC MultiSchema1.P1
GO
REVERT
GO

CREATE PROC OtherSchema.PA
AS
SELECT * FROM MultiSchema1.T1
SELECT * FROM MultiSchema2.T2
SELECT * FROM OtherSchema.TA
Go
GRANT EXEC ON OtherSchema.PA TO OwnsMultiSchema
GO
EXEC AS USER = 'OwnsMultiSchema'
GO
--works
EXEC OtherSchema.PA
GO
REVERT
GO

Редактировать 2:

  • Мы не используем «перекрестное владение базой данных»
  • Безопасность на уровне строк - красная сельдь и не имеет значения: мы не используем ее повсюду

Ответы [ 3 ]

22 голосов
/ 06 февраля 2010

Боюсь, что либо ваше описание, либо ваша концепция цепочки владения неясны, поэтому позвольте мне начать с этого:

«Цепочка владения» просто означает тот факт, что при выполнении хранимой процедуры (или представления) на SQL Server текущая исполняемая партия временно получает права / разрешения Владельца sProc (или Владельца схемы sProc) при выполнении этого Код SQL Таким образом, в случае sProc, Пользователь не может использовать эти привилегии для того, чтобы сделать что-то, что код sProc не реализует для них. Обратите внимание, что он никогда не приобретает Идентичность Владельца, только его права, временно (однако, EXECUTE AS ... делает это).

Таким образом, типичный подход для обеспечения безопасности:

  1. Поместите все таблицы данных (и все представления, не связанные с безопасностью) в их собственную схему, назовем ее [data] (хотя обычно используется [dbo], потому что она уже существует и слишком привилегирована для Схема пользователя). Убедитесь, что ни один из существующих пользователей, схем или владельцев не имеет доступа к этой схеме [данных].

  2. Создайте схему с именем [exec] для всех sProcs (и / или, возможно, любых представлений безопасности). Убедитесь, что владелец этой схемы имеет доступ к схеме [data] (это легко сделать, если вы сделаете dbo владельцем этой схемы).

  3. Создайте новую роль БД с именем «Пользователи» и предоставьте ей EXECUTE доступ к схеме [exec]. Теперь добавьте всех пользователей к этой роли. Убедитесь, что ваши пользователи имеют только права Connect и не имеют доступа к какой-либо другой схеме, включая [dbo].

Теперь ваши пользователи могут получить доступ к данным, только выполнив sProcs в [exec]. Они не могут получить доступ к каким-либо другим данным или выполнять любые другие объекты.

Я не уверен, что это отвечает на ваш вопрос (потому что я не был уверен, что именно был вопрос), поэтому не стесняйтесь перенаправить меня.


Что касается безопасности на уровне строк, вот как я всегда делаю это со схемой безопасности выше:

  1. Я всегда реализую безопасность на уровне строк как серию представлений, которые зеркально обтягивают каждую таблицу и сравнивают личность пользователя (обычно с Suser_Sname () или одним из других) со списком безопасности, введенным из кода безопасности в самом ряду. Это Security-Views.

  2. Создайте новую схему под названием [rows], предоставьте ее владельцу доступ к схеме [data] и ничего больше. Поместите все Security-Views в эту схему.

  3. Отменить доступ владельца [exec] к схеме [data] и вместо этого предоставить ему доступ к данным к схеме [lines].

Готово. Теперь защита на уровне строк была реализована путем прозрачного помещения ее между sProcs и таблицами.


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

CREATE proc [TestCnxOnly].[spShowProc_Security_NoEX]  as
--no "With Execute as Owner" for this version
--create User [UserNoLogin] without login
--Grant connect on database :: TestSecurity to Guest
--alter database TestSecurity set trustworthy on

--Show current user context:
select current_user as current_
, session_user as session
, user_name() as _name
, suser_name() as [suser (sproc)]
, suser_sname() as sname
, system_user as system_


--Execute As Login = 'UserNoLogin'
select current_user as current_
, session_user as session
, user_name() as _name
, suser_name() as [suser (after exec as)]
, suser_sname() as sname
, system_user as system_

EXEC('select current_user as current_
, session_user as session
, user_name() as _name
, suser_name() as [suser (in Exec(sql))]
, suser_sname() as sname
, system_user as system_')

EXEC sp_ExecuteSQL N'select current_user as current_
, session_user as session
, user_name() as _name
, suser_name() as [suser (in sp_Executesql)]
, suser_sname() as sname
, system_user as system_'

--Revert
select current_user as current_
, session_user as session
, user_name() as _name
, suser_name() as [suser (aftr revert)]
, suser_sname() as sname
, system_user as system_

[РЕДАКТИРОВАТЬ: исправленная версия кода)

8 голосов
/ 06 февраля 2010

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

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

Что касается вашего второго вопроса о безопасности на уровне строк: безопасность на уровне строк в действительности не существует в версиях SQL Server 2014 и более ранних версий, как функция, предлагаемая движком. У вас есть различные обходные пути, и эти обходные пути на самом деле лучше работают с подписанием кода, чем с цепочкой владения. Поскольку sys.login_token содержит сигнатуры контекста и контрсигнатуры, вы можете выполнять более сложные проверки, чем в контексте цепочки владения.

Начиная с версии 2016 SQL Server полностью поддерживает безопасность на уровне строк .

4 голосов
/ 06 февраля 2010

Вы можете:

Grant Execute On Schema::[schema_name] To [user_name]

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

...