12. 查詢數據庫帳號的全部權限

在SQL Server數據庫中,登陸帳號分類以下:sql

(1) SQL帳號,須要單獨設置密碼,好比:sa;數據庫

(2) Windows帳號,登陸windows的帳號,好比: administrator,不須要另設密碼;windows

(3) Windows Group 帳號, 爲本地用戶組或域用戶組,將組添加到登陸,組成員不須要單首創建登陸;服務器

查看Windows帳號,是否屬於某一個/多個用戶組:架構

exec xp_logininfo 'windows_acount','ALL'  --域用戶格式爲:domain_name\account_name

如下腳本,均假設最終登陸帳號爲:test_login,全部數據庫對應的user爲test_userdom

 

. 有沒有權限ide

1. 檢查有沒有登陸權限函數

--是否存在有效的登陸帳號:是否被禁用,sql login還有:密碼是否過時,是否被鎖定
select is_disabled, loginproperty(name,'Isexpired') is_expired, loginproperty(name,'Islocked') is_locked, * 
from sys.server_principals
where name = 'test_login'

  

2. 檢查有沒有訪問某數據庫的權限測試

USE DBA
GO

--檢查是否有數據庫的CONNECT權限便可
select b.* from sys.database_principals a
inner join sys.database_permissions b
on a.principal_id = b.grantee_principal_id
where SUSER_SNAME(a.sid) = 'test_login'
and b.permission_name = 'CONNECT'

--老的系統表sysusers也能夠檢查
SELECT name, hasdbaccess,* FROM sysusers a
WHERE SUSER_SNAME(a.sid) = 'test_login'

若是有不少個數據庫,寫個遊標1個個去檢查便可。spa

 

3. 檢查有沒有某個對象的權限

檢查有沒有某個對象的權限,通常是去嘗試運行下腳本比較直觀,若是去查各類權限表,角色錯綜複雜時,很難分辨;

SQL Server 2008以後引入了HAS_PERMS_BY_NAME這個函數,它能夠檢查當前帳號的各類權限,檢查其餘用戶須要用EXECUTE AS來切換:

USE DBA
GO
EXECUTE AS user = 'test_user'
GO
--對象權限
SELECT HAS_PERMS_BY_NAME('Sales.SalesPerson', 'OBJECT', 'INSERT');
SELECT HAS_PERMS_BY_NAME('sp_send_dbmail', 'OBJECT', 'EXEC');
--架構權限
SELECT HAS_PERMS_BY_NAME('test_schema', 'SCHEMA', 'SELECT');
REVERT;
GO

對因而否有登陸、訪問數據庫的權限,用這個函數也能夠判斷:

USE master
GO
EXECUTE AS login = 'test_login'
GO
--登陸權限,本機前2個參數爲空便可
SELECT HAS_PERMS_BY_NAME(NULL, NULL, 'CONNECT SQL');
REVERT;
GO

USE DBA
GO
EXECUTE AS user = 'test_user'
GO
--數據庫權限
SELECT HAS_PERMS_BY_NAME(db_name(), 'DATABASE', 'CONNECT');
REVERT;

 

. 有哪些權限

權限能夠直接分配給帳號,也能夠分配給帳號所屬的role,因此要把帳號自身權限、所屬role權限合併纔是最終的帳號權限。

Windows帳號權限還能夠經過用戶組分配,因此還要檢查這個Windows帳號有沒有屬於某個用戶組,若是有還須要加上這個用戶組的權限;

下面的腳本,僅檢查單個用戶/用戶組權限。

1. 實例級的權限

use master
GO
declare @svr_principal_name varchar(1024)
set @svr_principal_name = 'test_login'

declare @svr_principal_id int
select @svr_principal_id = principal_id 
from sys.server_principals p
where p.name = @svr_principal_name

if OBJECT_ID('tempdb..#tmp_svr_role','U') is not null
    drop table #tmp_svr_role;
create table #tmp_svr_role
(
member_principal_id     int,
member_principal_name   varchar(512),
role_principal_id       int, 
role_principal_name     varchar(512)
)

--獲取登陸帳號的全部server role, 從sql server 2012開始,server role能夠自定義,成員僅可爲fixed server role
;with tmp
as
(
select * from sys.server_role_members 
where member_principal_id = @svr_principal_id
union all
select rm.* from sys.server_role_members rm
inner join tmp 
on rm.member_principal_id = tmp.role_principal_id
)
insert into #tmp_svr_role 
select a.member_principal_id, b.name,
       a.role_principal_id, c.name
 from tmp a
inner join sys.server_principals b
on a.member_principal_id = b.principal_id
inner join sys.server_principals c
on a.role_principal_id = c.principal_id

--登陸帳號自身權限, sys.server_permissions不包含fixed server role權限,同時手動排除掉public權限
select a.principal_id as member_principal_id, a.name as member_principal_name,
       null as role_principal_id, null as role_principal_name,
       b.permission_name, b.state_desc
from sys.server_principals a
inner join sys.server_permissions b
on a.principal_id = b.grantee_principal_id
where a.principal_id = @svr_principal_id
and b.permission_name <> 'CONNECT SQL'
union all
--server role權限,包含fixed server role和自定義的server role
select a.member_principal_id, a.member_principal_name,
       a.role_principal_id, a.role_principal_name,
       isnull(b.permission_name,'Fixed Server-Level Role: '+role_principal_name) as permission_name, isnull(b.state_desc,'GRANT') as state_desc
from #tmp_svr_role a
left join sys.database_permissions b
on a.role_principal_id = b.grantee_principal_id
union all
--public server role權限,不能夠取消public權限,它是每一個登陸帳號的最小權限,僅可鏈接數據庫實例
select @svr_principal_id as member_principal_id,@svr_principal_name as member_principal_name,
       principal_id as role_principal_id, name as role_principal_name, 
       'CONNECT SQL' as permission_name, 'GRANT' as state_desc
from sys.server_principals
where name = 'public'
Instance-Level Permissions

注意:服務器角色的權限能夠作什麼具體的事情,exec sp_srvrolepermission 有大體的介紹,可是也並無所有列出每一種數據庫操做,由於有些操做是被更高級的操做包含的。

 

2. 數據庫級的權限

僅列出數據庫級別的權限,具體的對象名稱並無列出。

use DBA
GO
declare @svr_principal_name varchar(1024)
set @svr_principal_name = 'test_login'

declare @db_principal_id    int,
        @db_principal_name  varchar(512)
select @db_principal_id = principal_id,
       @db_principal_name = name
from sys.database_principals p
where SUSER_SNAME(sid) = @svr_principal_name

if OBJECT_ID('tempdb..#tmp_db_role','U') is not null
    drop table #tmp_db_role;
create table #tmp_db_role
(
member_principal_id     int,
member_principal_name   varchar(512),
role_principal_id       int, 
role_principal_name     varchar(512)
)

--獲取登陸帳號在當前數據庫的全部database role
;with tmp
as
(
select * from sys.database_role_members 
where member_principal_id = @db_principal_id
union all
select rm.* from sys.database_role_members rm
inner join tmp 
on rm.member_principal_id = tmp.role_principal_id
)
insert into #tmp_db_role 
select a.member_principal_id, b.name,
       a.role_principal_id, c.name
 from tmp a
inner join sys.database_principals b
on a.member_principal_id = b.principal_id
inner join sys.database_principals c
on a.role_principal_id = c.principal_id

--登陸帳號在當前數據庫的自身權限, sys.database_permissions不包含fixed database role權限,同時手動排除掉public權限
select a.principal_id as member_principal_id, a.name as member_principal_name,
       null as role_principal_id, null as role_principal_name,
       b.permission_name, b.state_desc
from sys.database_principals a
inner join sys.database_permissions b
on a.principal_id = b.grantee_principal_id
where a.principal_id = @db_principal_id
and b.permission_name <> 'CONNECT'
union all
--database role權限,包含fixed database role和自定義的database role
select a.member_principal_id, a.member_principal_name,
       a.role_principal_id, a.role_principal_name,
       isnull(b.permission_name,'Fixed Database-Level Role: '+role_principal_name) as permission_name, isnull(b.state_desc,'GRANT') as state_desc
from #tmp_db_role a
left join sys.database_permissions b
on a.role_principal_id = b.grantee_principal_id
union all
--public database role權限,不能夠取消public權限,它是每一個登陸帳號映射到當前數據庫的最小權限,僅可鏈接當前數據庫
select @db_principal_id as member_principal_id, @db_principal_name as member_principal_name,
       principal_id as role_principal_id, name as role_principal_name, 
       'CONNECT' as permission_name, 'GRANT' as state_desc
from sys.database_principals
where name = 'public'
Database-Level Permissions

注意:sysadmin的帳號在數據庫裏可能並無作映射,但權限是有的,隱式映射的用戶是dbo

 

3. 對象級的權限

sys.database_permissions有不少對象類型,major_id, minor_id取決於class_desc,不一樣的對象關聯不一樣的系統表/視圖,腳本里僅列出了最多見的OBJECT_OR_COLUMN, SCHEMA對象權限。

--創建測試用的架構,對象,列
use DBA
GO
if object_id('test_grant','U') is not null
    drop table test_grant
GO
create table test_grant(c1 int, c2 int, c3 int)
grant select (c1, c2) on test_grant to test_user;

if object_id('test_schema.test_t1','U') is not null
    drop table test_schema.test_t1
GO
if exists(select 1 from sys.schemas where name  = 'test_schema')
    drop schema test_schema
GO
create schema test_schema
create table test_schema.test_t1(c1 int, c2 int)
grant select on schema::test_schema to test_user;
GO

--開始獲取對象權限
use DBA
GO
declare @svr_principal_name varchar(1024)
set @svr_principal_name = 'test_login'

declare @db_principal_id    int,
        @db_principal_name  varchar(512)
select @db_principal_id = principal_id,
       @db_principal_name = name
from sys.database_principals p
where SUSER_SNAME(sid) = @svr_principal_name

if OBJECT_ID('tempdb..#tmp_db_role','U') is not null
    drop table #tmp_db_role;
create table #tmp_db_role
(
member_principal_id     int,
member_principal_name   varchar(512),
role_principal_id       int, 
role_principal_name     varchar(512)
)

--獲取登陸帳號在當前數據庫的全部database role
;with tmp
as
(
select * from sys.database_role_members 
where member_principal_id = @db_principal_id
union all
select rm.* from sys.database_role_members rm
inner join tmp 
on rm.member_principal_id = tmp.role_principal_id
)
insert into #tmp_db_role 
select a.member_principal_id, b.name,
       a.role_principal_id, c.name
 from tmp a
inner join sys.database_principals b
on a.member_principal_id = b.principal_id
inner join sys.database_principals c
on a.role_principal_id = c.principal_id

--登陸帳號在當前數據庫的自身對象權限(OBJECT_OR_COLUMN)
select a.principal_id as member_principal_id, a.name as member_principal_name,
       null as role_principal_id, null as role_principal_name,
       o.name as major_name, c.name as minor_name,
       b.permission_name, b.state_desc
from sys.database_principals a
inner join sys.database_permissions b
on a.principal_id = b.grantee_principal_id
left join sys.objects o
on b.major_id = o.object_id
left join sys.columns c 
on (b.major_id = c.object_id and b.minor_id = c.column_id)
where a.principal_id = @db_principal_id
and b.class_desc = 'OBJECT_OR_COLUMN'
union all
--登陸帳號在當前數據庫的自身對象權限(SCHEMA)
select a.principal_id as member_principal_id, a.name as member_principal_name,
       null as role_principal_id, null as role_principal_name,
       s.name as major_name, null as minor_name,
       b.permission_name, b.state_desc
from sys.database_principals a
inner join sys.database_permissions b
on a.principal_id = b.grantee_principal_id
left join sys.schemas s
on b.major_id = s.schema_id
where a.principal_id = @db_principal_id
and b.class_desc = 'SCHEMA'
union all
--database role的對象權限(OBJECT_OR_COLUMN)
select a.member_principal_id, a.member_principal_name,
       a.role_principal_id, a.role_principal_name,
       o.name as major_name, c.name as minor_name,
       b.permission_name, b.state_desc
from #tmp_db_role a
inner join sys.database_permissions b --inner join, 僅自定義的database role
on a.role_principal_id = b.grantee_principal_id
left join sys.objects o
on b.major_id = o.object_id
left join sys.columns c 
on (b.major_id = c.object_id and b.minor_id = c.column_id)
where b.class_desc = 'OBJECT_OR_COLUMN'
union all
--database role的對象權限(SCHEMA)
select a.member_principal_id, a.member_principal_name,
       a.role_principal_id, a.role_principal_name,
       s.name as major_name, null as minor_name,
       b.permission_name, b.state_desc
from #tmp_db_role a
inner join sys.database_permissions b --inner join, 僅自定義的database role
on a.role_principal_id = b.grantee_principal_id
left join sys.schemas s
on b.major_id = s.schema_id
where b.class_desc = 'SCHEMA'
/*
union all
--public role有一些系統視圖的select權限,能夠忽略
select a.principal_id as member_principal_id, a.name as member_principal_name,
       null as role_principal_id, null as role_principal_name,
       o.name as major_name, c.name as minor_name,
       b.permission_name, b.state_desc
from sys.database_principals a
inner join sys.database_permissions b
on a.principal_id = b.grantee_principal_id
left join sys.all_objects o
on b.major_id = o.object_id
left join sys.all_columns c 
on (b.major_id = c.object_id and b.minor_id = c.column_id)
where a.name = 'public'
*/
Object-Level Permissions

注意:若是對象的權限是經過role衍生的,而不是直接分配給user或者role,那麼並不會被列出來。試想sysadmin 的角色,難道要列出全部數據庫的全部對象嗎?

 

. 查看本身的權限

1. 有沒有登陸權限

登陸失敗並不必定是沒權限,仍是找別人來檢查本身帳號的登陸權限吧;

 

2. 有沒有數據庫訪問權限

--列出全部可訪問的數據庫
SELECT *
FROM sys.databases
WHERE HAS_DBACCESS(name) = 1

  

3. 有沒有對象訪問權限

用上面提到HAS_PERMS_BY_NAME函數,它能夠檢查當前帳號的各類權限;

SELECT HAS_PERMS_BY_NAME('test_sp', 'Object' , 'Execute')
SELECT HAS_PERMS_BY_NAME('test', 'Database' , 'Execute')

  

4. 有哪些權限

--實例級權限
SELECT * FROM fn_my_permissions(NULL, 'SERVER'); 
--數據庫級權限
SELECT * FROM fn_my_permissions ('DBA', 'DATABASE'); 
--對象權限,只能一個個對象檢查,不能一次返回全部對象權限,和HAS_PERMS_BY_NAME相似
SELECT * FROM fn_my_permissions ('test_grant', 'OBJECT'); 

 用於檢查本身權限的方法,一樣也能夠檢查其餘帳號,用EXECUTE AS切換帳號便可。

相關文章
相關標籤/搜索