The order of access control elements in an access control list is the following:

  1. explicit Deny elements
  2. explicit Allow elements
  3. inherited Deny elements
  4. inherited Deny elements

It is also called the canonical order.


Any order that doesn’t follow the semantic above, hasn’t got to be wrong. In fact you can define an order that solves your situation (some MS software does). But you shouldn’t do this where a user can find and edit it (like regkeys and files), otherwise the security descriptor editor in Windows Explorer and registry editor will show you a nasty warning. Moreover if you mix them up, the result of an AccessCheck may be difficult to understand for the user (bad user experience). And eventually, the unusual order could also create a security risk because a user could access a resource although it is explicitly denied. It happens when the user is (accidentally) granted access by placing an allow ACE in front of a deny ACE and both ACEs pointing to the same SID. The reason comes from the fact that an access check iterates through the (linear) access control list and stops when the first SID was found. So the first SID wins and defines whether access is granted or denied.


Did you know? JWSCL creates the canonical order automatically! So you don’t have to worry.

uses JwsclAcl, JwsclDescriptor;

var Desc : TJwSecurityDescriptor;
begin
Desc := TJwSecurityDescriptor.Create;

Desc.DACL.Add(TJwDiscretionaryAccessControlEntryDeny.Create(nil, [afInheritedAce], GENERIC_ALL, Sid4));
Desc.DACL.Add(TJwDiscretionaryAccessControlEntryAllow.Create(nil, [afInheritedAce], GENERIC_ALL, Sid3));
Desc.DACL.Add(TJwDiscretionaryAccessControlEntryAllow.Create(nil, [], GENERIC_ALL, Sid1));
Desc.DACL.Add(TJwDiscretionaryAccessControlEntryDeny.Create(nil, [], GENERIC_ALL, Sid2));

The result can be seen here:

  1. deny explicit Sid2
  2. allow explicit Sid1
  3. deny inherited Sid4
  4. allow inherited Sid3