数据库安全性控制:
- 1、用户标识与身份鉴别
- 2、访问控制
- 3、视图定义与查询修改
- 4、数据库加密技术
- 5、安全审计
定义:
数据库安全性控制要求尽可能杜绝所有可能的非法访问数据库行为,不管它们是故意的还是无意的。一个安全的数据库系统既要保证没有访问权限的用户不能访问数据库,又要保证有访问权限的用户能够访问数据库。安全性控制就是实现数据库各种安全策略的功能集合,并通过这一些安全策略构建安全模型,从而确保数据库系统的安全性。(P5)
数据库安全性控制就像是给数据库这个 "大仓库" 设置的一套安保系统,用来确保只有被允许的人能访问和操作里面的数据,防止数据被非法获取、篡改或破坏 。
rm -rf /
数据库安全性控制中的访问控制,就像是给数据库这个 "大仓库" 制定的详细规则,决定了谁(用户或应用程序)能以何种方式(操作权限)访问仓库里的哪些 "物品"(数据对象) 。确保用户对数据库只能进行需要经过授权的有关操作。

1. 用户标识与身份鉴别
用户标识与身份鉴别是保障数据库安全的关键环节,就像是数据库的 "门卫",确保只有合法用户能进入并操作数据库。
用户标识
用户标识是数据库为每个合法用户分配的独一无二的 "身份标签",用于区分不同用户。它就好比每个人的身份证号,是识别用户的基础。在 SQL Server 中,常见的用户标识方式有:
- 用户名:这是最普遍的用户标识。数据库管理员会为每个用户创建一个唯一的用户名,通常遵循一定的命名规则,比如以字母开头,可包含字母、数字和特定字符等。例如,"admin""user_01" 等。用户名在整个数据库系统内或特定数据库中具有唯一性,方便数据库系统识别和管理不同用户。
- 登录名:在 SQL Server 中,登录名用于连接到 SQL Server 实例。登录名与 Windows 账户或 SQL Server 账户相关联。如果使用 Windows 身份验证模式,登录名可以是 Windows 域账户或本地账户;若采用 SQL Server 身份验证模式,登录名则是 SQL Server 特定创建的账户。登录名在整个 SQL Server 实例范围内是唯一的。
身份鉴别
身份鉴别是基于用户标识,进一步确认用户 "身份" 真实性的过程,确保声称自己是某个用户的实体确实是该用户。SQL Server 主要通过以下方式进行身份鉴别:
在SQL Server中,有两种主要的身份验证模式:
- Windows身份验证:利用Windows操作系统的用户账户和密码进行验证。如果用户已经通过Windows系统的认证登录到计算机,当连接SQL Server时,系统会自动利用该用户在Windows中的身份进行验证,无需再次输入数据库特定的用户名和密码。这种方式安全性较高,因为Windows系统本身具备强大的安全机制。
- SQL Server身份验证:用户需要提供特定的SQL Server用户名和密码来连接数据库。这种方式适用于非Windows域环境,或者需要为外部用户提供数据库访问权限的场景。但需要注意妥善保管好SQL Server的用户名和密码,防止泄露。
数据库登陆名和数据库用户名是有差别的,在一个数据库中是一一相对应的关系。如果把数据库比作一个大厦,那么数据库登录名就是进入大厦的通行证,而用户名则是进入大厦房间的钥匙,如果每个房间看做是SQL数据库(大厦)的一个数据库,那么每个登陆名可以在每一个数据库中创建一个用户,如果没有创建用户,则登陆名就只能纯粹的登陆数据库,什么事情都干不了。
登录名是一个可由安全系统进行身份验证的安全主体或实体。 用户需要使用登录名连接到 SQL Server。
sql
CREATE LOGIN Jack WITH PASSWORD = '1qaz!QAZ' /*, DEFAULT_DATABASE = STUDENT; 这里如果不指定数据库的话,默认为master数据库*/
GO
CREATE LOGIN Jack WITH PASSWORD = '1qaz!QAZ'
MUST_CHANGE, CHECK_EXPIRATION = ON; /*MUST_CHANGE 选项要求用户在首次连接服务器时更改此密码*/
GO
(ps:密码是区分大小写的。 密码应始终至少包含八个字符,并且不能超过 128 个字符。 密码可以包含 a-z、A-Z、0-9 和大多数非字母数字字符。 密码不能包含单引号或 登录名)
1、姓名+符号+数字(不安全)
2、古诗+符号+数字
新建数据库用户
用户是数据库级别安全主体。 登录名必须映射到数据库用户才能连接到数据库。 一个登录名可以作为不同用户映射到不同的数据库,但在每个数据库中只能作为一个用户进行映射。 在部分包含数据库中,可以创建不具有登录名的用户(没有登录名的用户。 不能登录,但可以被授予权限)。 数据库内的权限是向数据库用户而不是向登录名授予和拒绝授予的。
sql
-- 创建登录名和创建用户可以一起写,这里先创建了一个名为Alice的用户,登录密码是:henry626626
CREATE LOGIN Alice
WITH PASSWORD = '1qaz!QAZ' /*, DEFAULT_DATABASE = STUDENT; 这里不指定的话,默认为master数据库*/
GO
-- 给刚刚创建的登录名Alice创建一个数据库用户Alice
CREATE USER Alice FOR LOGIN Alice;
GO
-- 创建没有登录名的用户。不能登录,但可以被授予权限
CREATE USER Mark WITHOUT LOGIN;
通过该SQL语句快速查看所有的用户:
sql
--查看所有用户
exec sp_helpuser;
sql
-- 先创建了一个名为Alice的用户,登录密码是:henry626626
CREATE LOGIN Alice
WITH PASSWORD = '1qaz!QAZ'; /*, DEFAULT_DATABASE = STUDENT; */
GO /*GO是批处理的标志*/
-- 给刚刚创建的登录名Alice创建一个数据库用户Alice
CREATE USER Alice FOR LOGIN Alice;
GO
经存在这个登录名了所以新建登录名拒绝执行
sql
CREATE LOGIN Alice WITH PASSWORD = '1qaz!QAZ';
CREATE USER Alice FOR LOGIN Alice;
sql
--查看所有用户
exec sp_helpuser;
以下代码同样可以达到新建登录名和用户的目的
sql
exec sp_addlogin '登录名', '密码', '选择的数据库';
exec sp_adduser '登录名', '用户名';
2. 访问控制
目的:
确保用户对数据库只能进行需要经过授权的有关操作
数据库管理系统规定(DBMS):若用户想要操作数据库中的数据,则必须有相应的权限。
2.1 访问控制的组成:
- 定义存取权限: 指明确规定主体(如用户、角色等)对客体(如数据库表、视图、存储过程等)能够执行哪些操作的过程 。(在数据库中,为了保证用户只能访问其具有存取权限的数据,必须预先对每个用户定义存取权限。)
(P8语句)
sql
-- 创建Employees表
CREATE TABLE Employees1 (
EmployeeID INT PRIMARY KEY,
EmployeeName NVARCHAR(50),
DepartmentID INT,
Salary DECIMAL(10, 2),
HireDate DATE,
);
-- 插入示例数据到Employees表
INSERT INTO Employees1 (EmployeeID, EmployeeName, DepartmentID, Salary, HireDate)
VALUES (101, 'zhangsan', 1, 5000.00, '2020 - 01 - 01'),
(102, 'lisi', 2, 7000.00, '2021 - 03 - 15'),
(103, 'wangwu', 1, 5500.00, '2020 - 05 - 20'),
(104, 'zhaoliu', 3, 6000.00, '2022 - 02 - 28');
sql
// 要授予用户User1对Employees表的SELECT权限
GRANT SELECT ON Employees TO Alice;
// 授予多个权限,如对Employees表的SELECT、INSERT和UPDATE权限:
GRANT SELECT, INSERT, UPDATE ON Employees TO Alice;
- 检查存取权限:对于通过鉴定获得权限的用户(即确认为合法用户),系统会根据其存取权限对其各种操作请求进行控制,确保该用户只能执行合法操作。
sql
// SQL Server 会在执行前检查User1是否具有对Employees表的SELECT权限。如果之前通过GRANT语句授予了该权限,则查询可以正常执行;如果没有授予,系统会返回权限不足的错误信息。
SELECT * FROM Employees1;
2.2 访问控制策略:
自主访问控制(DAC)、强制访问控制(MAC)、基于角色的访问控制(RBAC)、基于属性的访问控制(ABAC)
1. 自主访问控制(DAC):
在 DAC 策略下,数据库对象(如表格、视图、存储过程等)的所有者有权自行决定哪些主体(用户或角色)可以访问该对象,以及授予这些主体何种类型的访问权限。这种访问控制方式给予了对象所有者较大的自主决策权,就好比你自己盖了一栋房子,你可以自由决定让哪些人进入房子,以及他们能在房子里做什么。
sql
// 授予权限:使用GRANT语句为用户或角色授予对数据库对象的访问权限。
// 例如,假设用户Alice创建了一个名为Employees的表,她可以将查询
// 该表的权限授予用户Jack:
GRANT SELECT ON Employees TO Jack;
// Bob现在有权查询Employees表中的数据。如果Alice希望Jack还能插入新
// 的数据行到表中,她可以进一步执行:
GRANT INSERT ON Employees TO Jack;
sql
// 拒绝权限:通过DENY语句,对象所有者可以明确拒绝某个主体对特定对象
// 的访问权限。例如,如果Alice不想让Bob删除Employees表中的数据,她
// 可以执行:
DENY DELETE ON Employees TO Jack;
// 即使Jack通过其他途径(如所属角色被授予了删除权限)可能获得了删除权限,
// 这里的DENY设置也会优先,阻止他执行删除操作。
sql
// 撤销权限:使用REVOKE语句可以收回之前授予主体的权限。比如,Alice如果后悔
// 授予Jack插入数据的权限,可以执行:
REVOKE INSERT ON Employees FROM Jack;
2. 强制访问控制(MAC):
- 强制访问控制(Mandatory Access Control,MAC)是一种严格的访问控制策略,它基于系统设定的安全级别来限制主体对客体的访问,不像自主访问控制(DAC)那样由对象所有者自主决定权限。
- 基本原理
a.安全标签设定:系统为每个主体和客体都分配一个安全标签,这个标签代表了它们的安全级别。安全级别通常形成一个严格的层次结构,比如 "绝密" > "机密" > "秘密" > "公开"。例如,在军事数据库中,涉及战略计划的数据客体可能被标记为 "绝密",普通士兵的基本信息客体可能标记为 "秘密"。主体方面,高级将领的安全级别可能是 "绝密",普通士兵则可能是 "秘密"。
b.访问决策依据:只有当主体的安全级别等于或高于客体的安全级别时,主体才能访问该客体。这是一种强制性的规则,不依赖于用户或对象所有者的意愿。比如,一个安全级别为 "机密" 的主体,只能访问安全级别为 "机密"、"秘密" 或 "公开" 的客体,而无法访问 "绝密" 级别的客体。 - 实现方式
a.系统层面的支持:实现 MAC 需要操作系统和数据库管理系统的紧密配合。操作系统负责管理主体(如用户进程)的安全级别,数据库管理系统则负责为数据库客体(如表、视图等)分配和管理安全标签,并在主体尝试访问客体时,依据安全级别进行访问控制检查。例如,在一些专为高安全性需求设计的操作系统(如某些军用操作系统)与相应的数据库系统集成时,能够实现这种严格的 MAC 机制。
b.安全标签管理:数据库管理员负责为数据库中的各类客体分配合适的安全标签。这需要对数据的敏感性和重要性有深入的了解。同时,操作系统也会根据用户的角色、职责等因素为主体分配相应的安全级别。例如,在企业环境中,数据库管理员会根据数据的保密程度,将财务报表数据标记为 "机密",员工考勤数据标记为 "秘密"。对于企业员工,高级管理人员可能被赋予 "机密" 级别的访问权限,普通员工则被赋予 "秘密" 级别。
(了解即可)
在 SQL Server 中,原生并没有直接提供完整且典型的强制访问控制(MAC)实现方式,但可以借助一些功能和第三方工具来模拟或实现部分 MAC 特性。
利用 Windows 安全机制结合 SQL Server 角色
Windows 安全级别映射:
首先利用 Windows 操作系统的安全特性来设定用户的安全级别。例如,通过 Windows 组策略可以将不同用户或用户组划分为不同安全等级,如 "高安全等级组""中安全等级组" 等。
在 SQL Server 中,创建与这些 Windows 组对应的登录名。例如,假设 Windows 系统中有一个名为 "HighSecurityGroup" 的高安全等级组,可以使用以下语句创建对应的 SQL Server 登录:
sql
CREATE LOGIN [DOMAIN\HighSecurityGroup] FROM WINDOWS;
SQL Server 角色与权限设置:
创建不同权限级别的 SQL Server 数据库角色,每个角色对应不同安全级别数据的访问权限。例如,创建一个用于访问高敏感数据的角色 "HighSensitivityRole":
sql
CREATE ROLE HighSensitivityRole;
为该角色授予对高敏感数据对象(如表、视图等)的相应权限,比如对 "TopSecretData" 表的查询权限:
sql
GRANT SELECT ON TopSecretData TO HighSensitivityRole;
将之前创建的对应 Windows 组的 SQL Server 登录添加到相应角色中。例如,将 "HighSecurityGroup" 对应的登录添加到 "HighSensitivityRole" 角色:
sql
ALTER ROLE HighSensitivityRole ADD MEMBER [DOMAIN\HighSecurityGroup];
这样,属于 "HighSecurityGroup" 的 Windows 用户登录 SQL Server 后,由于其所属角色 "HighSensitivityRole" 的权限,就能够访问高敏感数据,实现了一定程度上基于安全级别的访问控制。
- 借助第三方安全工具
第三方安全软件集成:一些专业的数据库安全管理软件支持 MAC - like 的功能。这些软件可以对 SQL Server 数据库进行深度集成,为数据库中的对象(表、列等)和用户分配安全标签。
3. 基于角色的访问控制(RBAC):
RBAC在用户和权限之间增加了一个中间桥梁-角色。管理员将权限授予角色,并通过指定用户为特定角色为用户授权,极大简化授权管理。
支持工人的三大管理原则:最小权限原则,责任分离原则,数据抽象原则。
实现方式 - SQL Server
- 创建角色:使用CREATE ROLE语句在 SQL Server 中创建角色。例如,创建一个名为 "SalesRole" 的角色,用于销售部门员工:
sql
CREATE ROLE SalesRole;
- 分配权限给角色:使用GRANT语句为角色授予对数据库对象的权限。假设存在一个存储销售数据的 "SalesData" 表,为 "SalesRole" 角色授予对该表的查询和插入权限:
sql
GRANT SELECT, INSERT ON SalesData TO SalesRole;
- 用户与角色关联:使用ALTER ROLE语句将用户添加到相应角色中。例如,将用户 "User1" 添加到 "SalesRole" 角色:
sql
ALTER ROLE SalesRole ADD MEMBER User1;
这样,用户 "User1" 就通过 "SalesRole" 角色获得了对 "SalesData" 表的查询和插入权限。
4.基于属性的访问控制(ABAC)
以课本内容为准
3. 视图定义与查询修改

案例解析
假如把案例中的系统看成一个大型的数据库,那么案例中的故事我们可以用数据库中的视图机制更好地去理解。
视图的使用
案例中的大臣BCD,都拥有不同的视图View_B、View_C、View_D,不同的大臣查看到的内容是不同的,这就是利用视图进行数据安全访问的好处。
视图只是定义了一个查询,视图中的数据是从基表中获取,这些数据在视图被引用时动态的生成。由于视图基于数据库中的其他对象,因此一个视图只需占用数据字典中保存其定义的空间,而无需额外的存储空间,视图也会随着基表的变化而变化。( 例如,在一个包含员工信息表(Employees)的数据库中,你可能只想看到特定部门(如销售部)的员工姓名和薪资信息,就可以创建一个视图来实现这个需求。 )

视图创建:
sql
// 1. 创建数据表
// 我们创建两个表,一个Employees表用于存储员工信息,另一个Departments表用
// 于存储部门信息,并且Employees表通过DepartmentID与Departments表关联。
-- 创建Departments表
-- 创建名为Departments的表,用于存储部门相关信息
CREATE TABLE Departments (
-- 定义DepartmentID列,数据类型为整数(INT),并且设置为主键
-- 主键用于唯一标识表中的每一行数据,确保DepartmentID的唯一性
DepartmentID INT PRIMARY KEY,
-- 定义DepartmentName列,数据类型为最多可存储50个字符的Unicode字符串(NVARCHAR(50))
-- 该列用于存储部门的名称
DepartmentName NVARCHAR(50)
);
-- 创建Employees表
CREATE TABLE Employees (
EmployeeID INT PRIMARY KEY,
EmployeeName NVARCHAR(50),
DepartmentID INT,
Salary DECIMAL(10, 2),
HireDate DATE,
FOREIGN KEY (DepartmentID) REFERENCES Departments(DepartmentID)
);
-- 插入示例数据到Departments表
INSERT INTO Departments (DepartmentID, DepartmentName)
VALUES (1, '销售部'),
(2, '研发部'),
(3, '财务部');
-- 插入示例数据到Employees表
INSERT INTO Employees (EmployeeID, EmployeeName, DepartmentID, Salary, HireDate)
VALUES (101, '张三', 1, 5000.00, '2020 - 01 - 01'),
(102, '李四', 2, 7000.00, '2021 - 03 - 15'),
(103, '王五', 1, 5500.00, '2020 - 05 - 20'),
(104, '赵六', 3, 6000.00, '2022 - 02 - 28');
// 2. 创建视图
// 假设我们要创建一个视图,显示每个部门的员工数量、平均薪资以及部门名称。
CREATE VIEW DepartmentStatistics AS //创建视图声明,DepartmentStatistics是新创建视图的名称,你可以将其理解为一个虚拟表的名字。AS关键字之后定义了该视图的数据来源和处理逻辑。
SELECT
d.DepartmentName,
COUNT(e.EmployeeID) AS EmployeeCount,
AVG(e.Salary) AS AverageSalary
FROM
Departments d //指定数据来源之一为Departments表,并给它取了别名d。
JOIN
Employees e ON d.DepartmentID = e.DepartmentID //使用JOIN关键字将Employees表(别名e)与Departments表进行连接。连接条件是Departments表中的DepartmentID列与Employees表中的DepartmentID列相等。这一步确保了我们可以将员工信息与对应的部门信息关联起来,以便后续按部门进行统计。
GROUP BY
d.DepartmentName; //GROUP BY关键字用于将结果按Departments表中的DepartmentName进行分组
// 3. 视图的验证
// 查询视图:通过查询视图,验证视图是否按照预期返回数据
SELECT * FROM DepartmentStatistics;
// 数据变化验证:对底层表进行数据插入、更新或删除操作,然后
// 再次查询视图,验证视图数据是否相应更新。
INSERT INTO Employees (EmployeeID, EmployeeName, DepartmentID, Salary, HireDate)
VALUES (105, '孙七', 1, 5300.00, '2023 - 01 - 10');
// 再次查询视图:
SELECT * FROM DepartmentStatistics;
视图修改:
前提条件:并非所有视图都支持修改数据,一般来说,基于单个表且不包含聚合函数、GROUP BY、DISTINCT等复杂操作的简单视图更容易满足可修改条件
sql
-- 创建一个简单视图,用于查看和修改员工姓名
CREATE VIEW EmployeeNameView AS
SELECT EmployeeID, EmployeeName
FROM Employees;
-- 使用UPDATE语句通过视图修改员工姓名
UPDATE EmployeeNameView
SET EmployeeName = '新名字'
WHERE EmployeeID = 101;
// 上述代码首先创建了一个EmployeeNameView视图
// ,它从Employees表中选择了EmployeeID和EmployeeName
// 列。然后,使用UPDATE语句通过这个视图将EmployeeID为
// 101 的员工姓名修改为 "新名字"。由于这个视图基于单个
// 表且没有复杂操作,所以可以通过它来修改底层表的数据。
通过视图删除数据 :
(前提条件和上面一致)
sql
-- 创建一个简单视图,用于查看和删除员工记录
CREATE VIEW EmployeeSimpleView AS
SELECT EmployeeID, EmployeeName, DepartmentID
FROM Employees;
-- 使用DELETE语句通过视图删除员工记录
DELETE FROM EmployeeSimpleView
WHERE EmployeeID = 102;
sql
-- 创建原始员工表(假设这是现有系统中的表)
CREATE TABLE Employees
(
EmployeeID INT PRIMARY KEY,
Name NVARCHAR(100),
IDCard NVARCHAR(18), -- 身份证号(需要加密)
Phone NVARCHAR(20), -- 手机号(需要加密)
Salary DECIMAL(10,2), -- 工资(需要加密)
Department NVARCHAR(50), -- 部门(不需要加密)
HireDate DATE -- 入职日期(不需要加密)
);
-- 插入一些测试数据
INSERT INTO Employees VALUES
(1, '张三', '110101199001011234', '13800138000', 15000.00, '技术部', '2020-01-01'),
(2, '李四', '110101199002021235', '13900139000', 18000.00, '市场部', '2019-06-01'),
(3, '王五', '110101199003031236', '13700137000', 12000.00, '人事部', '2021-03-15');