本文属于SQL Server安全专题系列
随着元数据的使用频率越来越高,安全性也越来越凸显,因为从元数据中可以得到很多不应该随意暴露的系统信息。所以,绝大部分的元数据并不能随意被查看,通常都需要授权。
比如当一个用户A被授权查询B表,那么这个用户A就自动获得了在sys.tables和sys.objects中关于B表的信息。否则他无法真正使用这个B表。
如果需要查看那些没有权限访问的对象的元数据,可以使用VIEW DEFINITION权限来实现。VIEW DEFINITION可以授权到库层面或者实例层面,如果是实例层面,可以通过查看整个实例的元数据来实现某些元数据驱动的自动化脚本。同时也不需要过度授权。
由于某些对象属于权限结构之外,所以这些对象并不能制动授予VIEW DEFINITION权限,以分区为例。每个表可以跨三个分区进行拆分: 一个用于行内(in-row)数据, 另一个用于 LOB (大对象) 数据, 第三个用于overflow数据。因为它们不能直接访问,所以无法对分区分配权限。
在这种情况下,每个登录必须具有的public角色就可以用来查看关联的元数据,这个是VIEW DEFINITION不能做到的。public可以看到的元数据有:
- sys.partition_functions
- sys.partition_range_values
- sys.partition_schemes
- sys.data_spaces
- sys.filegroups
- sys.destination_data_spaces
- sys.database_files
- sys.allocation_units
- sys.partitions
- sys.messages
- sys.schemas
- sys.configurations
- sys.sql_dependencies
- sys.type_assembly_usages
- sys.parameter_type_usages
- sys.column_type_usages
但是正如上面说的,可见则存在风险。特别是对SQL注入防范比较差的应用,假设攻击者通过SQL注入在AdventureWorks2016上执行下面语句:
SELECT 1 + name FROM sys.tables
此时返回报错信息如下:
这种方式叫“Forced error message”,姑且直译为“强制错误信息”或者“强制信息披露”,这些错误信息暴露了以下可用于攻击的信息:
- 数据库中有一个表叫SalesTaxRate。
- 应用程序可以查询某些元数据。
- 应用程序可能以高权限帐号运行。
这些信息怎么用呢?比如,如果应用程序总是以单用户运行(假设一直都用sa来使用数据库),那么总有一些表是允许这个用户访问甚至操作的。然后通过修改查询, 使其按包含通配符字符串%user% 或%login% 的表进行筛选。一旦得到了信息,那么就可以开始攻击或者篡改信息。
这个故事说明,不要总是把安全性归咎在数据库上面,系统就是一个完整的体系,环环相扣。所以不仅帐号要有权限控制,元数据和应用程序都应该要有权限控制,核心原则还是最小权限控制。