在前一篇文章中,我简单的说明了 DACL 的数据结构组成,以及简单的存取方法,如果数据长度愈长的话,可以设定的权限就愈多,也可以有更多的组合,但数据量仍然可以控制在很小的长度,这是因为在 DACL 中,每个权限都是一个旗标值 (flag),而一个 bit 就代表一个旗标,所以 bit 多的话旗标就愈多,一个 byte 可以容纳 8 个 bits,也就是可以有 8 种旗标,之所以会选择位来作为旗标,是因为 bit 的值不是 0 就是 1,单纯有力。
在前一篇文章中,我简单的说明了 DACL 的数据结构组成,以及简单的存取方法,如果数据长度愈长的话,可以设定的权限就愈多,也可以有更多的组合,但数据量仍然可以控制在很小的长度,这是因为在 DACL 中,每个权限都是一个旗标值 (flag),而一个 bit 就代表一个旗标,所以 bit 多的话旗标就愈多,一个 byte 可以容纳 8 个 bits,也就是可以有 8 种旗标,之所以会选择位来作为旗标,是因为 bit 的值不是 0 就是 1,单纯有力。
例如,如果系统中有 C, R, U, D 四种权限,那么我们可以定义一个 byte 中的前 4 个位分别代表 C, R, U, D 的权限,所以可以有这样的设计:
byte _permission = new byte();
this._permission = 0x02; // Read permission.
这时 _permission 的 bit 分布是 00000010 (0x02),而第二个 bit R 的值为 1,代表允许 R 的权限,但 C, U, D 的权限是拒绝的。如果现在我们要加入 D 的权限 (00001000 = 0x08) 时,我们只要这样做:
this._permission = this._permission | 0x08; // OR operator.
此时 _permission 的 bit 分布会变成 00001010 (0x0a),第二和第四个 bit 均为 1,表示允许 R 和 D 的授权,而应用程序只要这样做验证:
bool allowResult = (this._permission & 0x02) == 0x02; // AND operator.
只要将权限表的 bit 值和要检查的权限值做 AND 运算,学过计算机概论的人应该都知道,AND 运算之下只有两个都是 1 时才会回传 1 (true),否则回传 0 (false),所以 _permission 和 0x02 的 AND 运算后,如果是允许授权的使用者,一定会得到 0x02 的结果值,否则会得到 0x00,表示没有获得授权。
当然,我们也可以直接进行复合授权的检验,例如 0x0a (同时检查有没有 R 和 D 的权限),一样经过 AND 运算,只要检查运算过的值等于 0x0a,就表示有被授权,否则就是没有授权。
另外,我们可以善用枚举值来表示权限,例如:
public enum AccessPermissions
{
Create = 0x01
Read = 0x01
Update = 0x01
Delete = 0x01
}
bool allowResult = (this._permission & AccessPermissions.Read) == AccessPermissions.Read; // AND operator.
一个 byte 最多可以放到 256 (值域 0-255, 0xff, 11111111),所以如果枚举权限要超过 8 个的话,可能就需要使用两个 byte 来存放,而且要用两个权限枚举,顺带提一件事,API 中有所谓的高位区 (high level bits) 与低位区 (low level bits) 的说法,这和 CPU 与数据的排列方式有关,以本文所指的例子,如果今天有 16 种权限要设定,就会需要用到两个 bytes,则本例会用 00000000 00000000,且由右往左读的顺序,这个方式称为 Little Endian (反向则是称为 Big Endian),因此在 bit stream 中,第一个 bit 一定是最右边的 bit,然后往左边移动,所以在前面的例子 00001010 是 C = 0, R = 1, U = 0, D = 1,而 00000011 为 C = 1, R = 1, U = 0, D = 0。在处理位 bit stream 时要注意这一点,否则很容易看错。有点离题了,前面提到枚举如果超过 8 个的话,在编译时会收到值不可超过 255 的错误消息。
在 .NET Framework 中也有一个对应的功能,称为 FlagAttribute,我们可以将上面的枚举改成:
[Flag]
public enum AccessPermissions
{
Create = 0x01,
Read = 0x02,
Update = 0x04,
Delete = 0x08
}
.NET Framework 会自动将值视为位枚举 (bit enumeration) 值,和使用 "
之所以花这些篇幅介绍位排列,是因为它会在设计 DACL 时扮演重要角色。
Reference:
Endianness: http://en.wikipedia.org/wiki/Endianness
FlagAttribute: http://weblogs.asp.net/wim/archive/2004/04/07/109095.aspx
原文:大专栏 [Security] 判别式存取控制表 (Discretionary Access Control List) 实践:旗目标概念