MSSQL-最佳实践-行级别安全解决方案

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS SQL Server,基础系列 2核4GB
访问控制,不限时长
简介: --- title: MSSQL-最佳实践-行级别安全解决方案 author: 风移 --- # 摘要 在SQL Server安全系列专题月报分享中,我们已经分享了:如何使用对称密钥实现SQL Server列加密技术、使用非对称密钥加密方式实现SQL Server列加密、使用混合密钥实现SQL Server列加密技术和列加密技术带来的查询性能问题以及相应解决方案四篇文章。本期月报我们

title: MSSQL-最佳实践-行级别安全解决方案

author: 风移

摘要

在SQL Server安全系列专题月报分享中,我们已经分享了:如何使用对称密钥实现SQL Server列加密技术、使用非对称密钥加密方式实现SQL Server列加密、使用混合密钥实现SQL Server列加密技术和列加密技术带来的查询性能问题以及相应解决方案四篇文章。本期月报我们分享使用SQL Server RLS(Row Level Security)行级别访问控制解决方案最佳实践。

问题引入

在很久以前我分享过一篇文章SQL Server使用视图做权限控制来实现行级别数据安全。今天我们把这个问题再次抛出来:不同用户访问同一张表,如何做到不同用户仅能访问属于自己及以下层级的数据。还是举例这个例子,比如:公司有CEO,Manger和普通的employee三种角色,CEO可以查看CEO、Manager和employee层级的数据;Manger只能查看Manger和employee的数据,不能查看CEO层级;而employee只能查看employee的数据,不能查看CEO和Manager级别的数据。今天我们把场景更进一步,要求用户仅能操作(DML)自己及下属的数据,不能跨级操作上层级的数据。

原理分析

SQL Server 2016版本引入了Row Level Security(以下简称RLS)新特性。这个特性本身不会对数据库中表数据做任何的加密和解密操作,而是基于用户定义的安全策略来限制和过滤表中行级别的数据,使得数据库引擎不会过多的暴露数据行,从而实现了非常简洁的访问控制方法,对用户的应用和客户端完全透明。因此,可以在用户不做任何代码修改情况下,简单两个步骤就可以轻松实现表行级别的数据安全访问控制。
 创建RLS过滤函数:用于控制哪些用户可以查看哪些数据的逻辑控制
 创建表级别的安全策略:用于实现表中数据行级别的安全访问控制

实现方法

按照问题引入部分的要求,我们需要实现数据查询访问控制和数据操作访问控制两个方面,以下是详细的实现方法步骤。

测试环境准备

还是沿用之前文章的测试场景数据,构建测试环境如下:

-- Create Test Database
IF DB_ID('Test') IS NULL
    CREATE DATABASE Test;
GO

USE Test
GO

--create three logins(CEO, manager, employee)

--create login CEO
IF EXISTS(
            SELECT *
            FROM sys.syslogins
            WHERE name = 'CEO')
BEGIN
      DROP LOGIN CEO;
END
GO
CREATE LOGIN CEO with password='CEODbo',check_policy = off;
GO

--create user CEO
IF USER_ID('CEO') is not null
        DROP USER CEO;
GO
CREATE USER CEO FOR LOGIN CEO;
GO

--create login Manager
IF EXISTS(
            SELECT *
            FROM sys.syslogins
            WHERE name = 'Manager')
BEGIN
      DROP LOGIN Manager;
END
GO
CREATE LOGIN Manager with password='ManagerDbo',check_policy = off;
GO

--create user manager
IF USER_ID('Manager') is not null
    DROP USER Manager;
GO
CREATE USER Manager FOR LOGIN Manager;
GO
       
--create login employee
IF EXISTS(
            SELECT *
            FROM sys.syslogins
            WHERE name = 'employee')
BEGIN
    DROP LOGIN employee;
END
GO
CREATE LOGIN employee with password='employeeDbo',check_policy = off;
GO

--create user employee
IF USER_ID('employee') is not null
        DROP USER employee
GO
CREATE USER employee FOR LOGIN employee;
GO

--create basic TABLE
IF OBJECT_ID('dbo.tb_Test_ViewPermission','u')is not null
    DROP TABLE dbo.tb_Test_ViewPermission
;
GO
CREATE TABLE dbo.tb_Test_ViewPermission
(
        id int identity(1,1) not null primary key
        ,name varchar(20) not null
        ,level_no int not null
        ,title varchar(20) null
        ,viewByCEO char(1) not null
        ,viewByManager char(1) not null
        ,viewByEmployee char(1) not null
        ,salary decimal(9,2) not null
);

--data init.
INSERT INTO dbo.tb_Test_ViewPermission
SELECT 'AA',0,'CEO','Y','N','N',1000000.0
union all
SELECT 'BB',1,'Manager','Y','Y','N',100000.0
union all
SELECT 'CC',2,'employee','Y','Y','Y',10000.0
;
GO

select * from dbo.tb_Test_ViewPermission

在没做权限控制的情况下,不论是CEO,Manger还是Employee用户,都能够看到所有的数据,如下:01.png

如此,无法做到表tb_Test_ViewPermission行级别的数据安全,也无法满足我们对数据行级别的查询和操作访问控制要求。

数据查询访问控制

让我们来看看如何实现行级别数据查询安全访问控制,需要实现如下三步:
 建立RLS过滤函数
 建立表级安全策略
 验证查询访问控制

建立RLS过滤函数

首先,建立RLS过滤函数,用于实现哪些用户可以查看哪些数据的访问控制逻辑,实现代码如下:

USE Test
GO
CREATE SCHEMA RLSFilterDemo;  
GO

-- Create filter title function
CREATE FUNCTION RLSFilterDemo.fn_getTitle(@title AS varchar(20))  
    RETURNS TABLE  
WITH SCHEMABINDING  
AS  
RETURN
    SELECT 1 AS result   
    WHERE USER_NAME() IN (
    SELECT A.title 
    FROM dbo.tb_Test_ViewPermission AS A
        INNER JOIN  dbo.tb_Test_ViewPermission AS B
        ON a.level_no <= B.level_no
    WHERE B.title = @title)
GO

稍微解释下代码实现:使用level_no来控制用户访问数据的层级,level_no值越小,层级越高,权限越大。即:level_no为0(对应CEO用户)可以查看level_no为0(对应CEO自己)、1(对应Manger用户)和2(对应Employee普通用户);level_no为1的能查看自己和Employee的数据;而level_no为2的仅能查看自己的数据行。当我们发现查询的用户和对应的title匹配的时候,我们就认为这个用户有相应的权限,即函数返回值为1,反之,则认为没有权限访问对应的行。

建立表级安全策略

接下来,我们基于前面的过滤函数建立表级别安全策略,并且使得这个安全策略了生效,代码如下:

USE Test
GO
-- create security policy base on the filter function
CREATE SECURITY POLICY TitleFilter  
ADD FILTER PREDICATE RLSFilterDemo.fn_getTitle(title)   
ON dbo.tb_Test_ViewPermission  
WITH (STATE = ON);
GO

验证查询访问控制

最后一步,我们需要对行级别安全的访问控制进行查询验证和测试:

USE Test
GO
-- grant permissions to three users.
GRANT SELECT ON dbo.tb_Test_ViewPermission TO CEO;  
GRANT SELECT ON dbo.tb_Test_ViewPermission TO Manager;  
GRANT SELECT ON dbo.tb_Test_ViewPermission TO employee;  

USE Test
GO

--CEO can read all of the data
EXECUTE AS USER='CEO'
SELECT WhoAmI = USER_NAME()
SELECT * FROM dbo.tb_Test_ViewPermission
REVERT;
GO

USE Test
GO
--Manager can read manager and employee's data, but except CEO's.
EXECUTE AS USER='Manager'
SELECT WhoAmI = USER_NAME()
SELECT * FROM dbo.tb_Test_ViewPermission
REVERT;
GO

USE Test
GO
--employee just can read employee's data, couldn't query CEO and Manger's.
EXECUTE AS USER='employee'
SELECT WhoAmI = USER_NAME()
SELECT * FROM dbo.tb_Test_ViewPermission
REVERT;
GO

结果展示如下图所示:
02.png

从截图来看,CEO可以查看任何人的数据行;Manger可以查看自己和Employee的数据行;而Employee仅能查看自己的数据。说明已经成功实现了行级别的用户查询访问控制,达到了我们既定的目的。

数据操作访问控制

成功完成数据查询行级别访问控制的实践之后,我们再深入一步实现行级别数据操作访问控制。即:实现用户仅能操作自己及下层级的数据(level_no大于等于自己),而不能操作自己层级之上(level_no小于自己)的数据。如果,我们不做任何的访问控制,任何有权限的用户都可以操作我们这张表的数据,如下:

-- First, take the security policy off.
ALTER SECURITY POLICY TitleFilter
WITH (STATE = OFF);
-- Try to perform the DML action to see the DML permission control
USE Test
GO
-- grant permissions to all users.
GRANT UPDATE, INSERT, DELETE ON dbo.tb_Test_ViewPermission TO CEO;
GRANT UPDATE, INSERT, DELETE ON dbo.tb_Test_ViewPermission TO Manager;
GRANT UPDATE, INSERT, DELETE ON dbo.tb_Test_ViewPermission TO employee;


USE Test
GO
--try to test INSERT by user employee
EXECUTE AS USER='employee'
SELECT WhoAmI = USER_NAME()

INSERT INTO dbo.tb_Test_ViewPermission
SELECT 'DD',2,'employee','Y','Y','Y',100.0;
SELECT * FROM dbo.tb_Test_ViewPermission;

UPDATE TOP(1) dbo.tb_Test_ViewPermission
SET name = 'EE'
WHERE name = 'DD';
SELECT * FROM dbo.tb_Test_ViewPermission;

DELETE TOP (1)
FROM dbo.tb_Test_ViewPermission
WHERE name = 'EE'
;
SELECT * FROM dbo.tb_Test_ViewPermission;

REVERT
GO
;

执行以上语句后,我们发现,employee用户插入一条数据DD,然后更新为EE,接下来将这条数据删除了。展示截图如下:
03.png

说明在没有行级别安全访问控制的情况下,任何有权限的用户都可以操作这张表所有的数据,无法实现数据行级别安全。

建立RLS过滤函数

同样,首先建立RLS过滤函数,用于实现哪些用户可以操作哪些数据的访问控制逻辑:

-- Here we go to show how to allow manager and restrict employee dml operation
USE Test
GO

CREATE SCHEMA RLSBlockDemo;
GO

CREATE FUNCTION RLSBlockDemo.fn_getTitle(@title AS varchar(20))
    RETURNS TABLE
WITH SCHEMABINDING
AS
    RETURN 
    SELECT 1 AS result
    WHERE USER_NAME() IN (
    SELECT A.title 
    FROM dbo.tb_Test_ViewPermission AS A
        INNER JOIN  dbo.tb_Test_ViewPermission AS B
        ON a.level_no <= B.level_no
    WHERE B.title = @title)
GO

建立表级别安全策略

基于RLS过滤函数,建立表级别操作控制的安全策略并且使其启用生效:

USE Test
GO
ALTER SECURITY POLICY TitleFilter
ADD BLOCK PREDICATE RLSBlockDemo.fn_getTitle(title)
ON dbo.tb_Test_ViewPermission AFTER INSERT;

ALTER SECURITY POLICY TitleFilter
WITH (STATE = ON);

验证操作访问控制

接下来,就是表级别操作的访问控制验证了,Manger用户可以完全操作自己的数据:

USE Test
GO
--try to test INSERT by user Manager
EXECUTE AS USER='Manager'
SELECT WhoAmI = USER_NAME()

INSERT INTO dbo.tb_Test_ViewPermission
SELECT 'DD',1,'Manager','Y','Y','Y',100.0;
SELECT * FROM dbo.tb_Test_ViewPermission;

UPDATE TOP(1) dbo.tb_Test_ViewPermission
SET name = 'EE'
WHERE name = 'DD';
SELECT * FROM dbo.tb_Test_ViewPermission;

DELETE TOP (1)
FROM dbo.tb_Test_ViewPermission
WHERE name = 'EE'
;
SELECT * FROM dbo.tb_Test_ViewPermission;

REVERT
GO

Manger首先插入了一条DD数据,然后更新为EE,最后将其删除,整个过程没有报错,均成功执行,如下图所示:
04.png

同样,Manger也可以操作Employee数据,即自己层级以下的数据(level_no大于自己):

USE Test
GO
--It's OK  to INSERT manger record by user Manager
EXECUTE AS USER='Manager'
SELECT WhoAmI = USER_NAME()

INSERT INTO dbo.tb_Test_ViewPermission
SELECT 'EE',2,'employee','Y','Y','N',100.0;
SELECT * FROM dbo.tb_Test_ViewPermission;
REVERT
GO
;

Manger插入了一条Employee的数据EE:
05.png

但是,Manger不能操作自己层级以上的数据(level_no小于自己),比如CEO的数据,如下代码:

USE Test
GO
--Failed to INSERT CEO record by user Manager
EXECUTE AS USER='Manager'
SELECT WhoAmI = USER_NAME()

INSERT INTO dbo.tb_Test_ViewPermission
SELECT 'DD',0,'CEO','Y','Y','Y',100.0;

REVERT
GO
;

Manger试图操作CEO的数据,会报告如下错误:

(1 row affected)
Msg 33504, Level 16, State 1, Line 286
The attempted operation failed because the target object 'Test.dbo.tb_Test_ViewPermission' has a block predicate that conflicts with this operation. If the operation is performed on a view, the block predicate might be enforced on the underlying table. Modify the operation to target only the rows that are allowed by the block predicate.
The statement has been terminated.

错误截图如下所示:
06.png

在完成数据行级别安全策略之后,我们可以成功实现用户数据行级别操作访问控制安全,达到我们既定安全目标。

最后总结

本期月报我们分享了使用SQL Server 2016引入的新特性 Row Level Security实现数据访问控制解决方案最佳实践,在用户无需对应用做任何改动的情况下实现表行级别数据查询和操作访问控制,使得最大限度保证表行级别数据安全。

相关实践学习
消息队列+Serverless+Tablestore:实现高弹性的电商订单系统
基于消息队列以及函数计算,快速部署一个高弹性的商品订单系统,能够应对抢购场景下的高并发情况。
云安全基础课 - 访问控制概述
课程大纲 课程目标和内容介绍视频时长 访问控制概述视频时长 身份标识和认证技术视频时长 授权机制视频时长 访问控制的常见攻击视频时长
目录
相关文章
|
4月前
|
SQL 存储 JSON
阿里云数据库 SelectDB 内核 Apache Doris 2.1.0 版本发布:开箱盲测性能大幅优化,复杂查询性能提升 100%
亲爱的社区小伙伴们,Apache Doris 2.1.0 版本已于 2024 年 3 月 8 日正式发布,新版本开箱盲测性能大幅优化,在复杂查询性能方面提升100%,新增Arrow Flight接口加速数据读取千倍,支持半结构化数据类型与分析函数。异步多表物化视图优化查询并助力仓库分层建模。引入自增列、自动分区等存储优化,提升实时写入效率。Workload Group 资源隔离强化及运行时监控功能升级,保障多负载场景下的稳定性。新版本已经上线,欢迎大家下载使用!
阿里云数据库 SelectDB 内核 Apache Doris 2.1.0 版本发布:开箱盲测性能大幅优化,复杂查询性能提升 100%
|
4月前
|
SQL 关系型数据库 数据库
阿里云数据库 RDS SQL Server版实战【性能优化实践、优点探析】
本文探讨了Amazon RDS SQL Server版在云数据库中的优势,包括高可用性、可扩展性、管理便捷、安全性和成本效益。通过多可用区部署和自动备份,RDS确保数据安全和持久性,并支持自动扩展以适应流量波动。可视化管理界面简化了监控和操作,而数据加密和访问控制等功能保障了安全性。此外,弹性计费模式降低了运维成本。实战应用显示,RDS SQL Server版能有效助力企业在促销高峰期稳定系统并保障数据安全。阿里云的RDS SQL Server版还提供了弹性伸缩、自动备份恢复、安全性和高可用性功能,进一步优化性能和成本控制,并与AWS生态系统无缝集成,支持多种开发语言和框架。
288 2
|
3月前
|
存储 NoSQL 数据管理
MongoDB关系处理:优化数据管理、提升性能的最佳实践
MongoDB关系处理:优化数据管理、提升性能的最佳实践
|
4月前
|
监控 NoSQL 测试技术
MongoDB性能最佳实践:如何制定更有效的基准测试?
感谢你与我们一起走过这段MongoDB性能最佳实践之旅,希望你能从中获取一些有用的信息
1790 3
|
4月前
|
存储 缓存 NoSQL
|
12月前
|
SQL 网络协议 Linux
MSSQL不出网文件落地上线方式
MSSQL不出网文件落地上线方式
123 0
|
12月前
|
关系型数据库 调度 数据库
直播预告 | PolarDB-PG 企业级特性 —— Shared Server特性详解
PolarDB-PG 提供了 Shared Server 内置连接池功能,实现了用户连接与后端进程的解绑。后端进程在运行时可以根据实时负载和进程污染情况进行动态转换。负载调度算法使用 Stall 机制弹性控制 Worker 数量,同时避免用户连接饿死。从根本上解决了高并发或者大量短连接带来的性能、稳定性问题。
|
SQL 关系型数据库 数据库
阿里云产品体系分为6大分类——云计算基础——数据库——关系型数据库——云数据库RDS SQL Server版
阿里云产品体系分为6大分类——云计算基础——数据库——关系型数据库——云数据库RDS SQL Server版自制脑图
103 0
阿里云产品体系分为6大分类——云计算基础——数据库——关系型数据库——云数据库RDS SQL Server版
|
消息中间件 Kubernetes 监控
通用数据库审计K8s部署实践
通用数据库审计是日志服务提供的一种轻量级、低成本数据库安全方案,在之前的文章《自建数据库没有审计方案?试试这套轻量级低成本方案》中介绍了通过部署Logtail和Packetbeat在应用服务器或者数据库服务器上的方法抓取数据库操作行为流量,从而实现数据库审计数据的采集。日志服务提供了开箱即用的审计报表和告警配置。 随着云原生技术的成熟,越来越多的应用部署在云原生环境,云原生环境的动态及灵活性给抓包工具带来了一些困难,本文主要介绍在K8s环境下如何部署这套轻量级、低成本审计方案。
570 0
通用数据库审计K8s部署实践
|
存储 SQL 运维
PG数据库生态选型思路与最佳实践
PG数据库生态选型思路与最佳实践
PG数据库生态选型思路与最佳实践