SQL Server 安全模型分三層:
CREATE LOGIN / sp_addlogin,決定「能否連線到伺服器」。CREATE USER / sp_grantdbaccess,將登入映射到資料庫,決定「能進哪個資料庫」。GRANT / DENY / REVOKE,決定「在資料庫裡能做什麼」。
CREATE LOGIN [AppUser] WITH PASSWORD = 'StrongP@ssw0rd!', DEFAULT_DATABASE = [AppDB];
-- 或對應 Windows 帳戶
CREATE LOGIN [DOMAIN\AppUser] FROM WINDOWS;
EXEC sp_addlogin 'AppUser', 'StrongP@ssw0rd!', 'AppDB';
USE AppDB;
CREATE USER [AppUser] FOR LOGIN [AppUser];
USE AppDB;
EXEC sp_grantdbaccess 'AppUser';
GRANT 權限清單 ON 物件 TO 受體;
-- 權限清單:SELECT, INSERT, UPDATE, DELETE, REFERENCES, EXECUTE, VIEW DEFINITION 等
-- 物件:TABLE, VIEW, PROCEDURE, FUNCTION, SYNONYM, SCHEMA 等
-- 受體:USER, ROLE, PUBLIC
USE AppDB;
-- 1. 授予單一資料表 SELECT, UPDATE
GRANT SELECT, UPDATE ON dbo.Orders TO AppUser;
-- 2. 授予結構描述層級權限 (一次套用該結構描述所有現有/未來物件)
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO AppUser;
-- 3. 授予預存程序執行權限
GRANT EXECUTE ON dbo.usp_GetOrderDetails TO AppUser;
-- 4. 授予角色 (再將使用者加入角色)
CREATE ROLE AppReadOnly;
GRANT SELECT ON SCHEMA::dbo TO AppReadOnly;
ALTER ROLE AppReadOnly ADD MEMBER AppUser;
-- 5. 撤銷權限
REVOKE UPDATE ON dbo.Orders FROM AppUser;
-- 明確拒絕 (優先於 GRANT)
DENY DELETE ON dbo.Orders TO AppUser;
| 角色 | 隱含權限 | 適用場景 |
|---|---|---|
db_datareader | 所有使用者表/檢視 SELECT | 報表/唯讀帳號 |
db_datawriter | 所有使用者表 INSERT/UPDATE/DELETE | ETL/寫入服務 |
db_ddladmin | CREATE/ALTER/DROP 結構描述物件 | 開發/部署帳號 |
db_securityadmin | 管理角色成員、權限 | DBA 代理 |
db_owner | 資料庫完全控制 | 資料庫擁有者 |
db_denydatareader | 拒絕所有 SELECT | 反模式,勿用 |
db_denydatawriter | 拒絕所有寫入 | 反模式,勿用 |
ALTER ROLE db_datareader ADD MEMBER AppUser; -- SQL 2012+
-- 舊版
EXEC sp_addrolemember 'db_datareader', 'AppUser';
| 角色 | 權限範圍 |
|---|---|
sysadmin | 伺服器完全控制 (含關機) |
securityadmin | 管理登入、密碼、伺服器層級權限 |
serveradmin | 伺服器組態選項 |
setupadmin | 連結伺服器、啟動程序 |
processadmin | 管理執行緒 (KILL) |
diskadmin | 管理磁碟檔案 |
dbcreator | 建立/修改/刪除資料庫 |
bulkadmin | 執行 BULK INSERT |
public | 所有登入隸屬,預設最小權限 |
-- 1. 列出資料庫使用者與角色成員
SELECT
dp.name AS UserName,
dp.type_desc AS UserType,
r.name AS RoleName
FROM sys.database_principals dp
LEFT JOIN sys.database_role_members drm ON dp.principal_id = drm.member_principal_id
LEFT JOIN sys.database_principals r ON drm.role_principal_id = r.principal_id
WHERE dp.type IN ('S','U','G') -- SQL, Windows, Group
ORDER BY dp.name, r.name;
-- 2. 列出物件層級權限
SELECT
dp.name AS Grantee,
obj.name AS ObjectName,
perm.permission_name,
perm.state_desc -- GRANT / DENY
FROM sys.database_permissions perm
JOIN sys.database_principals dp ON perm.grantee_principal_id = dp.principal_id
JOIN sys.objects obj ON perm.major_id = obj.object_id
WHERE perm.class = 1 -- OBJECT_OR_COLUMN
ORDER BY dp.name, obj.name;
-- 3. 檢查是否誤加入 db_denydatareader
SELECT dp.name
FROM sys.database_principals dp
JOIN sys.database_role_members drm ON dp.principal_id = drm.member_principal_id
JOIN sys.database_principals r ON drm.role_principal_id = r.principal_id
WHERE r.name = 'db_denydatareader';
建立使用者與授權的標準流程:CREATE LOGIN → CREATE USER → GRANT 最小權限 (物件/結構描述層級優先) → 必要時加入固定角色。避免使用 db_denydatareader/writer、避免直接授予 db_owner/sysadmin 給應用程式。定期執行權限稽核腳本,確保最小權限原則落實。