解決數(shù)據(jù)分權(quán)訪問----SQL 2016 行級(jí)安全解決方案

沈云狈癞,資深工程師履羞,微軟解決方案專

這個(gè)數(shù)據(jù)爆炸的年代峦萎,數(shù)據(jù)安全性不可忽視,很多客戶都曾經(jīng)無數(shù)次的問到這個(gè)問題如何解決數(shù)據(jù)讀取時(shí)候的安全性忆首,如何實(shí)現(xiàn)用戶分角色爱榔、分職位、分group來區(qū)分?jǐn)?shù)據(jù)糙及。簡單來講不同用戶在讀取數(shù)據(jù)時(shí)候详幽,得到的數(shù)據(jù)不同。如下:這是一張病人統(tǒng)計(jì)表浸锨。執(zhí)行的查詢是:

SELECT * FROM patients? 一共7條數(shù)據(jù)



而往往我們需要的是

根據(jù)不同醫(yī)生或者護(hù)士查到的病人不同唇聘,如:

這是 護(hù)士: “小昭”負(fù)責(zé)的病人



一般方法是關(guān)聯(lián)表,然后進(jìn)行篩選查詢

select * from patients a, staffDuties s,employees e

where

a.wing=s.wing and s.empid=e.empid

order by s.empid

是這樣的結(jié)果



這樣再去按照需要進(jìn)行where過濾揣钦。如



但是這樣做雳灾,代碼復(fù)雜,并且難于控制冯凹。安全性不高谎亩。因此在SQL2016里面出現(xiàn)了行級(jí)安全性來解決。

如何來解決呢宇姚。我們來看看實(shí)現(xiàn)的效果匈庭。

-- Impersonate various users in the system (for demo purposes)

EXECUTE ('SELECT * FROM patients;') AS USER = 'nurse_BartonC';?????? --3

EXECUTE ('SELECT * FROM patients;') AS USER = 'nurse_AllenM';??????? --4

EXECUTE ('SELECT * FROM patients;') AS USER = 'nurse_NightingaleF';? --2

EXECUTE ('SELECT * FROM patients;') AS USER = 'doctor_ApgarV';?????? --7

EXECUTE ('SELECT * FROM patients;') AS USER = 'doctor_CharcotJ';???? --7



執(zhí)行的相同的查詢語句:SELECT * FROM patients;只是按照不同的身份去執(zhí)行

而數(shù)據(jù)庫給出的結(jié)果完全是不同的,依賴于身份的權(quán)限浑劳。

在應(yīng)用上通過用戶登錄的信息獲得數(shù)據(jù)庫的權(quán)限阱持。記得反饋不同結(jié)果。那么如何實(shí)現(xiàn)的呢魔熏。這個(gè)測試庫的代碼如下:

CREATE DATABASE RLS_Hospital_Demo

USE RLS_Hospital_Demo -- note, if you're on Azure SQL Database, you must change the connection manually

go

CREATE TABLE [patients] (

patientId INT PRIMARY KEY,

name nvarchar(256),

room int,

wing int,

startTime datetime,

endTime datetime

)

CREATE TABLE [employees] (

empId int PRIMARY KEY,

name nvarchar(256),

databasePrincipalId int

)

CREATE TABLE [staffDuties] (

empId int,

wing int,

startTime datetime,

endTime datetime

)

CREATE TABLE [wings] (

wingId int PRIMARY KEY,

name nvarchar(128)

)

go

CREATE ROLE [nurse]

CREATE ROLE [doctor]

go

GRANT SELECT, UPDATE ON [patients] to [nurse]

GRANT SELECT, UPDATE ON [patients] to [doctor]

go

-- Create a user for each nurse & doctor (without logins to simplify demo)

-- Add to corresponding role (in practice, these could also be Windows Groups)

-- Add to employees table

CREATE USER [nurse_BartonC] WITHOUT LOGIN

ALTER ROLE [nurse] ADD MEMBER [nurse_BartonC]

INSERT INTO [employees] VALUES ( 1001, N'張三豐', DATABASE_PRINCIPAL_ID('nurse_BartonC'));

go

CREATE USER [nurse_AllenM] WITHOUT LOGIN

ALTER ROLE [nurse] ADD MEMBER [nurse_AllenM]

INSERT INTO [employees] VALUES ( 1002, N'小靜', DATABASE_PRINCIPAL_ID('nurse_AllenM') );

go

CREATE USER [nurse_NightingaleF] WITHOUT LOGIN

ALTER ROLE [nurse] ADD MEMBER [nurse_NightingaleF]

INSERT INTO [employees] VALUES ( 1003, N'小昭', DATABASE_PRINCIPAL_ID('nurse_NightingaleF'));

go

CREATE USER [doctor_ApgarV] WITHOUT LOGIN

ALTER ROLE [doctor] ADD MEMBER [doctor_ApgarV]

INSERT INTO [employees] VALUES ( 2001, N'張無忌', DATABASE_PRINCIPAL_ID('doctor_ApgarV'));

go

CREATE USER [doctor_CharcotJ] WITHOUT LOGIN

ALTER ROLE [doctor] ADD MEMBER [doctor_CharcotJ]

INSERT INTO [employees] VALUES ( 2002, N'令狐沖', DATABASE_PRINCIPAL_ID('doctor_CharcotJ'));

go

INSERT INTO wings VALUES( 1, N'North');

INSERT INTO wings VALUES( 2, N'South');

INSERT INTO wings VALUES( 3, N'Emergency');

go

INSERT INTO [patients] VALUES ( 01, N'田伯光', 101, 1, '12-17-2017',? '03-26-2017')

INSERT INTO [patients] VALUES ( 02, N'岳不群', 102, 1, '10-27-2016',? '05-27-2017')

INSERT INTO [patients] VALUES ( 05, N'鄧八公', 107, 1, '5-7-2016',? '11-6-2016')

INSERT INTO [patients] VALUES ( 03, N'丹青生', 203, 2, '3-8-2016',? '12-14-2016')

INSERT INTO [patients] VALUES ( 04, N'仇松年', 205, 2, '1-27-2016',? '12-5-2016')

INSERT INTO [patients] VALUES ( 06, N'于人豪', 301, 3, '1-31-2016',? null)

INSERT INTO [patients] VALUES ( 07, N'不戒', 308, 3, '6-15-2016',? '9-4-2016')

INSERT INTO [staffDuties] VALUES ( 1001, 1, '01-01-2016', '12-31-2016' )

INSERT INTO [staffDuties] VALUES ( 1001, 2, '01-01-2017', '12-31-2017' )

INSERT INTO [staffDuties] VALUES ( 1002, 1, '01-01-2016', '06-30-2016' )

INSERT INTO [staffDuties] VALUES ( 1002, 2, '07-01-2016', '12-31-2016' )

INSERT INTO [staffDuties] VALUES ( 1002, 3, '01-01-2017', '12-31-2017' )

INSERT INTO [staffDuties] VALUES ( 1003, 3, '01-01-2016', '12-31-2017' )

INSERT INTO [staffDuties] VALUES ( 2001, 1, '01-01-2016', '12-31-2016' )

INSERT INTO [staffDuties] VALUES ( 2001, 3, '01-01-2017', '12-31-2017' )

INSERT INTO [staffDuties] VALUES ( 2002, 1, '01-01-2016', '12-31-2017' )

go

-- END SETUP

創(chuàng)建好數(shù)據(jù)庫后衷咽。 創(chuàng)建行級(jí)安全性代碼

CREATE SCHEMA rls? ---創(chuàng)建行級(jí)安全性構(gòu)架

go

---創(chuàng)建一個(gè)內(nèi)聯(lián)表值函數(shù)

---根據(jù)用戶信息鸽扁。房間號(hào),開始時(shí)間镶骗,結(jié)束時(shí)間進(jìn)行過濾.

---如果是醫(yī)生就能查看所有的信息 返回1

CREATE FUNCTION rls.accessPredicate(@wing int, @startTime datetime, @endTime datetime)

RETURNS TABLE

WITH SCHEMABINDING

AS

RETURN SELECT 1 AS accessResult FROM

dbo.StaffDuties d INNER JOIN dbo.Employees e ON (d.EmpId = e.EmpId)

WHERE

(

-- nurses can only access patients who overlap with their wing assignments

IS_MEMBER('nurse') = 1

AND e.databasePrincipalId = DATABASE_PRINCIPAL_ID()

AND @wing = d.Wing

AND

(

d.endTime >= @startTime AND d.startTime <= ISNULL(@endTime, GETDATE())

)

)

OR

(

-- doctors can see all patients

IS_MEMBER('doctor') = 1

)

go

----創(chuàng)建過濾策略

---并且設(shè)置了更新策略桶现,也就是說只有讀權(quán)限沒有update權(quán)限

CREATE SECURITY POLICY rls.PatientsSecurityPolicy

ADD FILTER PREDICATE rls.accessPredicate(wing, startTime, endTime) ON dbo.patients,

ADD BLOCK PREDICATE rls.accessPredicate(wing, startTime, endTime) ON dbo.patients AFTER UPDATE

Go

結(jié)果就可以如上圖了:

另外執(zhí)行update結(jié)果



可以看到無法修改數(shù)據(jù)。直接從根本解決了數(shù)據(jù)訪問問題

那么問題又來了鼎姊!

普通的用戶不使用windows驗(yàn)證骡和,也不使用SQL用戶驗(yàn)證,也就是說所有用戶都是使用一個(gè)SQL連接用戶到數(shù)據(jù)庫相寇,這樣就玩不了慰于,因?yàn)闄?quán)限是一樣的。當(dāng)然微軟肯定會(huì)想到這點(diǎn)唤衫。給出了更好玩的方案:

我們來修改下策略:

alter? FUNCTION rls.accessPredicate(@wing int, @startTime datetime, @endTime datetime)

RETURNS TABLE

WITH SCHEMABINDING

AS

RETURN SELECT 1 AS accessResult FROM

dbo.StaffDuties d INNER JOIN dbo.Employees e ON (d.EmpId = e.EmpId)

WHERE

(

d.EmpId=CAST(SESSION_CONTEXT(N'empid') AS int)

AND @wing = d.Wing

)

Go

通過CAST(SESSION_CONTEXT(N'empid')來取得權(quán)限

---刪除老策略

drop SECURITY POLICY rls.PatientsSecurityPolicy

-----創(chuàng)建新策略

create SECURITY POLICY rls.PatientsSecurityPolicy

ADD FILTER PREDICATE rls.accessPredicate(wing, startTime, endTime) ON dbo.patients,

ADD BLOCK PREDICATE rls.accessPredicate(wing, startTime, endTime) ON dbo.patients AFTER UPDATE

go

執(zhí)行結(jié)果:



這樣的話只需要在用戶登錄系統(tǒng)時(shí)候 在 SESSION_CONTEXT中設(shè)置不同的用戶ID后婆赠,可以通過從Sales表進(jìn)行選擇,來模擬連接篩選战授。 在實(shí)踐中页藻,應(yīng)用程序負(fù)責(zé)在打開連接后在SESSION_CONTEXT中設(shè)置當(dāng)前用戶ID

語法:

EXEC sp_set_session_context @key=N'empid', @value=1003;

另外:

下面視圖可以看到策略權(quán)限

SELECT * FROM sys.security_policies

SELECT * FROM sys.security_predicates

go



這樣就可以用這個(gè)功能實(shí)現(xiàn)用戶很爽的安全性的管理。

立即訪問http://market.azure.cn

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末植兰,一起剝皮案震驚了整個(gè)濱河市份帐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌楣导,老刑警劉巖废境,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異筒繁,居然都是意外死亡噩凹,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門毡咏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驮宴,“玉大人,你說我怎么就攤上這事呕缭《略螅” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵恢总,是天一觀的道長迎罗。 經(jīng)常有香客問我,道長片仿,這世上最難降的妖魔是什么纹安? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上厢岂,老公的妹妹穿的比我還像新娘光督。我一直安慰自己,他們只是感情好咪笑,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布可帽。 她就那樣靜靜地躺著,像睡著了一般窗怒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蓄拣,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天扬虚,我揣著相機(jī)與錄音,去河邊找鬼球恤。 笑死辜昵,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的咽斧。 我是一名探鬼主播堪置,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼张惹!你這毒婦竟也來了舀锨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬榮一對情侶失蹤宛逗,失蹤者是張志新(化名)和其女友劉穎坎匿,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體雷激,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡替蔬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了屎暇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片承桥。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖根悼,靈堂內(nèi)的尸體忽然破棺而出凶异,到底是詐尸還是另有隱情,我是刑警寧澤番挺,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布唠帝,位于F島的核電站,受9級(jí)特大地震影響玄柏,放射性物質(zhì)發(fā)生泄漏襟衰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一粪摘、第九天 我趴在偏房一處隱蔽的房頂上張望瀑晒。 院中可真熱鬧绍坝,春花似錦、人聲如沸苔悦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玖详。三九已至把介,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蟋座,已是汗流浹背拗踢。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留向臀,地道東北人巢墅。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像券膀,于是被迫代替她去往敵國和親君纫。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法芹彬,類相關(guān)的語法蓄髓,內(nèi)部類的語法,繼承相關(guān)的語法雀监,異常的語法双吆,線程的語...
    子非魚_t_閱讀 31,598評(píng)論 18 399
  • 什么是SQL數(shù)據(jù)庫: SQL是Structured Query Language(結(jié)構(gòu)化查詢語言)的縮寫。SQL是...
    西貝巴巴閱讀 1,803評(píng)論 0 10
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 3,805評(píng)論 0 11
  • 50個(gè)常用的sql語句Student(S#,Sname,Sage,Ssex) 學(xué)生表Course(C#,Cname...
    哈哈海閱讀 1,226評(píng)論 0 7
  • 宗薩蔣揚(yáng)欽哲仁波切:“我無權(quán)給任何人任何建議会前,更不要說給中國人好乐,因?yàn)槲覍χ袊臍v史與文化了解的非常少。但因?yàn)槲矣?..
    以愛之名2017閱讀 182評(píng)論 0 0