SQL 授权机制

我们可能会给用户在数据库的某些部分上授予几种形式的权限。对数据的授权包括:

  • 授权读取数据
  • 授权插入新数据
  • 授权更新数据
  • 授权删除数据

每种这样类型的授权都称为一种权限( privilege )。我们们可以在数据库的某些特定部分(比如一个关系或视图)上授于用户所有这些类型的权限,或完全不授权,或授予这些权限的一个组合。
当用户提交查询或更新时, SQL 实现先基于该用户曾获得过的权限检查此査询或更新是否是授权过的如果此查询或更新没有经过授权,那么将被拒绝执行
除了数据上的授权之外,用户还可以被授予数据库模式上的权限,例如,可以允许用户创建、修改或删除关系。拥有某些形式的权限的用户还可以把这样的权限转授(授予)给其他用户,或者撤销(收回)一种之前授出的权限
权限的最终形式是被授予数据库管理员的。数据库管理员可以授权给新用户、可以重构数据库等。权限的这种形式和操作系统中的超级用户( superuser )、管理员或操作员的权限是类似的。


权限的授予和收回

SQL 标准包括选择(select)、插入(insert)、更新(update)和删除(delete)权限。所有权限(all privilege)这样的权限可以用作允许所有权限的简写形式一个创建了新关系的用户将被自动授予该关系上的所有权限
SQL 数据定义语言包括授予收回权限的命令。授权( grant )语句用来授予权限。此语句的基本形式为:

 grant <权限列表>
 on <关系名或视图名>
 to <用户/角色列表>;

权限列表( privilege list )允许在一条命令中授多个权限。
关系上的选择权限用于读取关系中的元组。下面的授权语句给数据库用户 Amit 和Satoshi 授予了 department 关系上的选择权限:

 grant select on department to Amit , Satoshi;

该授权使得这些用户可以在 department 关系上运行查询。
关系上的更新权限允许用户修改关系中的任意元组更新权限既可以在关系的所有属性上授予,也可以只在某些属性上授予。如果在授权语句中包括了更新权限,则被授予更新权限的属性列表可以出现在紧跟关键字 update 的括号中。该属性列表是可选项,如果省略属性列表,则授予的是关系的所有属性上的更新权限
下面的授权语句授予用户 Amit 和 Satoshi 在 department 关系的 budget 属性上的更新权限:

 grant update (budget) on department to Amit , Satoshi;

关系上的插入权限允许用户往关系中插人元组插入权限也可以指定一个属性列表;对关系所做的任何插人必须只针对这些属性,并且系统对其余属性要么赋缺省值(如果为这些属性定义了缺省值),要么将它们置为空( null )
关系上的删除权限允许用户从关系中删除元组
public 这个用户名是指系统的所有当前用户和将来的用户。因此,对 public 的授权隐含着对所有当前用户和将来用户的授权
在缺省情况下,被授予权限的用户/角色无权把此权限授予另一个用户/角色。 SQL 允许一个权限授予来指定接受者可以进一步把此权限授予另一个用户
值得注意的是: SQL 授权机制可以在整个关系上或一个关系的特定属性上授予权限。但是,它不允许在一个关系的特定元组上授权
我们使用收权( revoke )语句来收回权限。此语句的形式与授权几乎是一样的:

 revoke <权限列表>
 on <关系名或视图名>
 from <用户/角色列表>

因此,为了收回前面我们所授予的那些权限,我们写作:

revoke select on department from Amit , Satoshi;
revoke update (budget) on department from Amit , Satoshi;

如果被收回权限的用户已经把权限授予了另外的用户,则权限的收回会更加复杂。


角色

考虑在一所大学里不同人所具有的真实世界角色。每位教师必须在问一组关系上具有相同类型的权限。无论何时指派一位新的教师,他都必须被单独授予所有这些权限。
一种更好的方式是指明每位教师应该被授予的权限,并单独标识出哪些数据库用户是教师。系统可以利用这两条信息来确定每位教师的权限。当雇用了一位新的教师时,必须给他于配一个用户标识,并且必须将他标识为一位教师,而不需要重新单独授予教师权限。
角色( role )的概念适用于此观念。在数据库中建立一个角色集,可以给角色授予权限,就和给单个用户授权的方式完全一样。每个数据库用户被授予一组他有权扮演的角色(也可能是空的)。
可以授予用户的任何权限都可以授予角色。给用户授予角色就像给用户授予权限一样,在 SQL 中创建角色如下所示:

 create role instructor,

然后角色就可以像用户那样被授予权限,如这条语句所示:

grant select on takes 
to instructor ;

角色可以授予用户,也可以授予其他角色,如这些语句所示:

create role dean;
grant instructor to dean ;
grant dean to Satoshi ;

因此,一个用户或一个角色的权限包括:

  • 直接授予该用户/角色的所有权限
  • 授予该用户/角色所拥有的角色的所有权限

请注意可能存在着一个角色链:例如, teaching assistant 角色可能被授予所有的 instructor 。接着, instructor 角色被授予所有的 dean 。这样, dean 角色就继承了被授予 instructor 和 teaching _ assistant 角色的所有权限,还包括直接授予 dean 的权限。
当一个用户登录到数据库系统时,在此会话期间由该用户执行的动作拥有直接授予该用户的所有权限,以及(直接地或通过其他角色间接地)授予该用户所拥有的角色的所有权限。这样,如果一个用户 Amit 被授予了 dean 角色,用户 Amit 就拥有了直接授予 Amit 的所有权限,以及授予 dean 的权限,再加上授 instructor 和 teaching _ assistant 的权限,如果像上面那样,这些角色被(直接地或间接地)授予 dean 角色。
值得注意的是:基于角色的授权概念并没有在 SQL 中指定,但在很多的共享应用中,基于角色的授权被广泛应用于存取控制。


视图的授权

在我们的大学示例中,请考虑一位工作人员,他需要知道一个特定系(比如说地质系)里所有员工的工资。该工作人员无权看到其他系中员工的相关信息。因此,该工作人员对 instructor 关系的直接访问必须被禁止。但是,如果他要访问地质系的信息,他就必须得到一个视图上的访问权限,我们称该视图为geo_instructor ,它仅由属于地质系的那些 instructor 元组构成。该视图可以用 SQL 定义如下:

create view geo_instructor as 
(select *
from instructor 
where dept_name='Geology');

假设该工作人员发出如下 SQL 查询:

select *
from geo_instructor ;

该工作人员有权看到此查询的结果。但是,当查询处理器将此查询转换为数据库中实际关系上的查询时,它用视图的定义来取代对视图的使用,从而在 instructor上产生了一个查询。这样,系统必须在用视图定义来替换视图之前,就检查该工作人员的查询权限
创建视图的用户没必要获得该视图上的所有权限他仅得到的那些权限不会为他提供超越他已有权限的额外权限。例如,一个创建视图的用户不能得到视图上的更新权限,如果该用户在用来定义视图的关系上没有更新权限的话如果用户要创建一个视图,而此用户在该视图上不能获得任何权限,则系统会拒绝这样的视图创建请求。在我们的 geo_instructor 视图示例中,视图的创建者必须在 instructor 关系上具有选择权限。
SQL 支持创建函数和过程,继而在函数和过程中可以包括查询与更新。在函数或过程上可以授予执行( execute )权限,以允许用户执行该函数或过程。在缺省情况下和视图类似,函数和过程具有其创建者所拥有的所有权限。在效果上**,函数或过程的运行就像它被其创建者调用了那样**。
尽管这种方式在很多情况下是恰当的,但是它并非总是恰当的。从 SQL :2003开始,如果函数定义有一个额外的sql security invoker子句,那么它就在调用该函数的用户的权限下执行,而不是在函数定义者的权限下执行。这就允许所创建的函数库能够在与调用者相同的权限下运行。


模式的授权

SQL 标准为数据库模式指定了一种基本的授权机制:只有模式的拥有者才能够执行对模式的任何修改,比如创建或删除关系、増加或删除关系的属性,以及增加或删除索引
然而, SQL 提供了一种引用( references )权限,它允许用户在创建关系时声明外码。可以通过与更新权限类似的方式将 SQL 的引用权限授予特定属性。下面的授权语句允许用户 Mariano 创建这样的关系:它能够引用department关系的 dept_name 码作为外码。

grant references (dept_name) on department to Mariano;

初看起来,似乎没有理由不允许用户创建引用了其他关系的外码。但是,请回想一下:外码约束限制了被引用关系上的删除和更新操作。假定 Mariano 在关系 r 中创建了一个外码,它引用 department 关系的 dept_name属性,然后在 r 中插人一条属于地质系的元组。那么就再也不可能从 department 关系中将地质系删除,除非同时也修改关系 r 。这样,由 Mariano 定义的外码就限制了其他用户将来的操作,因此,需要有引用权限。
继续使用 department 关系的示例,如果要创建关系 r上的 check 约束,并且该约束有引用 department 的子査询,那么还需要有department上的引用权限。其原因与我们已给出的外码约束的情况类似,因为引用了一个关系的 check 约束会限制对该关系可能的更新。


权限的转移

获得了某些形式的授权的用户可能被允许将该授权传递给其他用户在缺省方式下,被授予权限的用户/角色无权把得到的权限再授予另外的用户/角色如果我们希望在授权时允许接受者把权限再传递给其他用户,可以在相应的授权命令后附加 with grant option 子句。例如,如果我们希望授予 Amit 在 department上的选择权限,并且允许 Amit 将该权限授予其他用户,我们写作:

grant select on department to Amit with grant option;

一个对象(关系/视图/角色)的创建者拥有该对象上的所有权限,包括给其他用户授权的权限
作为一个示例,请考虑大学数据库中 teaches 关系上更新权限的授予情况。假设最开始数据库管理员将 teaches 上的更新权限授予用户U1、U2和U3,他们接下来又可能将此权限传递给其他用户。指定的权限从一个用户传递到另一个用户的过程可以表示为授权图( authorization graph )。该图中的节点就是用户
请考虑 teaches 上更新权限所对应的授权图。如果用户 Ui将 teaches 上的更新权限授予Uj,则图中包含一条 Ui-Uj的边。图的根是数据库管理员。在如下所示的示例图中,请注意U1和U2都给用户 U5授过权,而U4只从U1处获得过授权。
一个用户具有权限的充要条件是:当且仅当存在从授权图的根(即代表数据库管理员的节点)到代表该用户的节点的路径
SQL 授权机制_第1张图片


权限的收回

假设数据库管理员决定收回用户U1的授权。由于U4从U1处获得过授权,因此该权限也应该被收回。可是, U5既从U1处又从U2处获得过授权。由于数据库管理员并没有从U2处收回 teaches 上的更新权限,因此U5继续拥有 teaches 上的更新权限。如果U2最终从U5处收回授权,则U5将失去权限。
一对狡猾的用户可能企图通过相互授权来破坏收回权限的规则。例如,U2最初由数据库管理员授予了一种权限,U2进而把此权限授予U3。假设U3现在把此权限授回给U2。如果数据库管理员从U2收回权限,看起来好像U2保留了通过U3获得的授权。然而,请注意一旦管理员从收回了权限,那么在授权图中就不存在从根到U2或U3的路径了。这样, SQL 保证从这两个用户那里都收回了权限
SQL 授权机制_第2张图片
正如我们刚才看到的那样,从一个用户/角色那里收回权限可能导致其他用户/角色也失去该权限。这一方式称作级联收权( cascading revocation )。在大多数的数据库系统中,级联是缺省方式。然而,收权语句可以声明限定( restrict )来防止级联收权

revoke select on department from Amit,Satoshi restrict;

在这种情况下,如果存在任何级联收权,则系统返回一个错误,并且不执行收权动作
可以用关键字 cascade 来替换 restrict ,以表示需要级联收权,然而, cascade可以省略,就像我们前述示例中那样,因为它是缺省方式
下面的收权语句仅仅收回授权选项,而并不是真正收回选择权限

revoke grant option for select on department from Amit ;

请注意一些数据库实现并不支持上述语法,它们采用另一种方式:收回权限本身,然后不带grant option子句重新授权
级联收权在许多情况下是不合适的。假定Satoshi具有dean角色,他将instructor授予Amit,后来dean角色从Satoshi收回(也许由于 Satoshi 离开了大学), Amit继续被雇用为教职工,并且还应该保持 instructor角色。
为了处理这种情况, SQL允许权限通过角色来授予,而不是通过用户来授予。 SQL 有一个与会话相关联的当前角色的概念。在缺省情况下,一个会话所关联的当前角色是空的(某些特殊情况除外)。与一个会话相关联的当前角色可以通过执行set role role_name来设置。指定的角色必须已经授予用户,否则set role语句会执行失败
为了将授权人的某种权限设置为与一个会话相关联的当前角色,只要当前角色不为空,我们就可以给授权语句增加子句:

granted by current role 

假设将instructor角色(或其他权限)授予Amit是用granted by current role子句实现的,当前角色被设置为dean而不是作为用户Satoshi的授权人。那么,从 Satoshi 处收回角色/权限(包括 dean 角色)就不会导致收回以dean角色作为授权人所授予的权限,即使 Satoshi 是执行该授权的用户;这样,即使在 Satoshi 的权限被收回后、Amit仍然能够保持instructor角色。


行级授权

我们已经学习过的授权类型适用于关系或视图级别一些数据库系统在关系中的特定元组级别提供了细粒度的授权机制
例如,假设我们希望允许学生在takes关系中查看他自己的数据,但不允许查看其他用户的那些数据。如果数据库支持,我们可以使用行级授权来强制实施此类限制。下面我们将描述 Oracle 中的行级授权;PostgreSQL 和 SQL Server 也使用概念上类似的机制来支持行级授权,但使用的是不同的语法。
Oracle 虚拟私有数据库( Virtual Private Database , VPD )功能支持如下所示的行级授权。它允许系统管理员将函数与关系相关联该函数返回一个谓词该谓词会自动添加到使用该关系的任何查询中。该谓词可以使用sys_context函数,它返回代表正在执行查询的用户的标识。对于我们的示例,学生需要访问他们在takes关系中的数据,我们将指定以下谓词与takes关系相关联:

ID=sys_context('USERENV','SESSIONUSER')

系统将此谓词添加到使用takes关系的每个査询的where子句中。其结果是,每名学生只能看到ID值与其ID 相匹配的那些takes元组。
VPD提供了关系的特定元组或行的级别上的授权,因此被称为行级授权( row - level authorization )机制。如上所述添加谓词的一个隐患是:它可能会显著改变查询的含义,例如,如果一个用户编写查询来查找所有课程的平均成绩,则他最终会得到他的成绩的平均值,而不是所有成绩的平均值。虽然系统会为重写的查询提供“正确”的答案,但用户可能认为该答案与其所提交的查询不对应。

你可能感兴趣的:(sql,数据库)