web-dev-qa-db-ja.com

SQL Server:スキーマを許可する方法は?

私が見たさまざまなスキーマ関連の質問に触発された...

所有権連鎖 を使用すると、ストアドプロシージャとテーブルの両方が同じスキーマにある場合、使用するテーブルに対する明示的なアクセス許可なしに、ストアドプロシージャでEXECUTEを付与できます。

別々のスキーマを使用する場合、異なるスキーマテーブルにXXXを明示的に付与する必要があります。所有権連鎖の例はそれを示しています。これは、ストアドプロシージャを実行しているユーザーがテーブルを直接読み書きできることを意味します。

これは、クラスのインスタンス変数に直接アクセスし、ゲッター/セッターをバイパスし、カプセル化を解除するようなものです。

また、行レベルのセキュリティを使用して、誰かが見るものを制限し、これをストアドプロシージャに適用します。

それでは、スキーマの分離をどのように維持し、テーブルへの直接アクセスを防ぐことができますか?

もちろん、ORMを使用する場合、またはストアドプロシージャを使用しない場合、質問は適用されません。しかし、私はnot誰かが私を啓発する必要があると感じた場合に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:

  • 「データベース間の所有権チェーン」を使用しません
  • 行レベルのセキュリティは赤いニシンであり、無関係です:どこでも使用しません
25
gbn

あなたの説明または所有権の連鎖の概念が不明確であるのではないかと心配しています。

「所有権の連鎖」とは、SQL Serverでストアドプロシージャ(またはビュー)を実行すると、現在実行中のバッチがそのSQLコードの実行中に一時的にsProcの所有者(またはsProcのスキーマの所有者)の権限を取得するという事実を指します。そのため、sProcの場合、ユーザーはこれらの特権を使用して、sProcコードが実装していないことを行うことはできません。 特に、一時的に所有者のIdentityを取得することはなく、その権利のみを取得することに注意してください(ただし、EXECUTE AS ...はこれを行います)。

したがって、これをセキュリティに活用する一般的なアプローチは次のとおりです。

  1. すべてのデータテーブル(およびセキュリティ以外のすべてのビュー)を独自のスキーマに入れて、[データ]と呼びましょう(通常、[dbo]は既に存在し、ユーザーのスキーマに対して特権が高いため使用されます)。既存のユーザー、スキーマ、または所有者がこの[データ]スキーマにアクセスできないことを確認してください。

  2. すべてのsProcs(および/またはセキュリティビュー)に対して[exec]というスキーマを作成します。このスキーマの所有者が[data]スキーマにアクセスできることを確認してください(dboをこのスキーマの所有者にすると簡単です)。

  3. 「Users」という新しいdb-Roleを作成し、[exec]スキーマへのEXECUTEアクセスを許可します。すべてのユーザーをこのロールに追加します。ユーザーが接続権限のみを持ち、[dbo]を含む他のスキーマへのアクセスを許可されていないことを確認してください。

これで、ユーザーは[exec]でsProcsを実行することによってのみデータにアクセスできます。他のデータにアクセスしたり、他のオブジェクトを実行することはできません。

これがあなたの質問に答えるかどうかはわかりません(質問が正確に何であるかが不確かだったため)。


行レベルのセキュリティについては、上記のセキュリティスキームで常に行う方法を示します。

  1. すべてのテーブルをミラーラップし、ユーザーのID(通常はSuser_Sname()または他のいずれかと)を行自体のセキュリティコードからキーが設定されたセキュリティリストと比較する一連のビューとして行レベルセキュリティを常に実装します。これらはセキュリティビューです。

  2. [rows]という名前の新しいスキーマを作成し、その所有者に[data]スキーマへのアクセス権のみを付与します。すべてのセキュリティビューをこのスキーマに配置します。

  3. [exec]所有者の[data]スキーマへのアクセスを取り消し、代わりに[rows]スキーマへのデータアクセスを許可します。

できた現在、行レベルのセキュリティは、sProcsとテーブルの間で透過的にスリップすることにより実装されています。


最後に、この不明瞭なセキュリティ機能がどれだけ機能し、それ自体と相互作用するかを覚えておくために使用するストアドプロシージャを示します(oops、修正バージョンのコード):

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_

[編集:コードの修正バージョン)

22
RBarryYoung

My 2c:所有権の連鎖はレガシーです。これは、代替手段がなかった日から始まり、今日の代替手段と比較すると安全ではなく、粗雑です。

代替案はスキーマの許可ではなく、代替案はコード署名です。コード署名を使用すると、プロシージャの署名に必要なアクセス許可を付与し、データアクセスを厳しく制御しながら、プロシージャに対する幅広い実行アクセスを付与できます。コード署名は、よりきめ細かくより正確な制御を提供し、所有権の連鎖ができる方法を悪用することはできません。スキーマ内で動作し、スキーマ全体で動作し、データベース全体で動作し、データベース間所有権チェーンの巨大なセキュリティホールを開く必要はありません。また、アクセス目的でオブジェクト所有権をハイジャックする必要はありません。プロシージャの所有者はどのユーザーでもかまいません。

行レベルのセキュリティに関する2番目の質問については、エンジンによって提供される機能として、SQL Serverバージョン2014以前には行レベルのセキュリティは実際には存在しません。さまざまな回避策があり、これらの回避策は、所有権の連鎖よりもコード署名の方が実際にうまく機能します。 sys.login_token にはコンテキスト署名と副署名が含まれているため、実際には、所有権連鎖コンテキストよりも複雑なチェックを実行できます。

バージョン2016以降、SQL Serverは 行レベルセキュリティ を完全にサポートしています。

8
Remus Rusanu

あなたはできる:

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

ユーザーがスキーマ内の任意のプロシージャを実行できるようにします。彼がそれらのすべてを実行できるようにしたくない場合は、ユーザーに対して特定のプロシージャの実行を明示的に拒否できます。この場合、拒否が優先されます。

4
Lyudmila