Security Checks

Filesystems play a key role in securing access to the files and directories they contain; in addition to storing the security information associated with each filesystem object, they must also enforce access restrictions based on that information. The implementor of virtual files, if desired, should generally handle security using one of the following options:

  • For filesystems which identify themselves as NTFS, security of virtual files should be handled using standard Windows security mechanisms: access control lists (ACLs).
  • For any filesystem, including NTFS, the implementor of virtual files can handle security by implementing custom security checks.

Each security handling method is described in more detail below, followed by additional information relevant for both.

Windows Security Mechanisms (ACLs)

The CBVirtualFile class can optionally advertise support for NTFS security attributes by enabling the UseWindowsSecurity property (and, as implied above, this is highly recommended for filesystems which identify as NTFS). When UseWindowsSecurity is enabled, the GetFileSecurity and SetFileSecurity events will fire anytime Windows needs to read or write security information. To correctly implement these events, applications must store and retrieve the OS-provided security information alongside the associated filesystem objects.

The CBFilter class can handle security-related events by adding the corresponding filter rules using the AddFilterRule method. When the rules are set, the BeforeGetFileSecurity, BeforeSetFileSecurity, AfterGetFileSecurity, and AfterSetFileSecurity events will fire anytime Windows needs to read or write security information. To correctly implement these events, applications must store and retrieve the OS-provided security information alongside the associated filesystem objects.

However, Windows doesn't handle the task of actually checking or enforcing access rights when sending requests to create or open filesystem objects, it's up to the implementor of virtual files to do so. Therefore, when such requests arrive, the application must retrieve the previously-stored security information for the applicable file or directory, and then use that information to validate whether the process attempting access has sufficient rights to do so.

The aforementioned validation can be done easily using the Windows API's AccessCheck function, which validates a process's access rights against some object's security attributes; please refer to its documentation for more information. Once the application has performed the access validation, it should either allow or deny the request according to the results.

Custom Security Checks

Both the CBFilter class and CBVirtualFile class also offer a number of methods that applications can use to help implement their own custom security checks. The two most notable of these methods are CBFilter's GetOriginatorProcessName, which returns the name of the process that initiated the request, and GetOriginatorToken, which returns the system-defined security token of the process that initiated the request.

The latter is particularly useful when used with various methods in the Windows API, such as the GetTokenInformation function, which can be used to obtain various pieces of information about the object the token is associated with.

Implementing Security Checks

Regardless of which security handling method is used, there are a number of things to keep in mind when implementing security checks in general. First, consider that effective security enforcement does not require that all event handlers perform security checks. Applications are technically free to deny any file-related event due to a failed security check. However, it isn't actually meaningful to perform security checks in all event handlers in the first place, and unnecessary security checks will decrease an application's overall performance.

For example, it makes sense to validate access rights in the BeforeCreateFile and BeforeOpenFile event handlers of CBFilter and CreateFile and OpenFile event handlers of CBVirtualFile, but not in the event handlers, related to file reading or writing. If an application denies a file create/open request made by some process, then that process won't be able to make a subsequent read/write request; therefore, applications can safely assume that all read/write requests come from processes whose access rights they have already verified. Similar logic can be applied for directories and directory enumerations. (Note that this is not an exhaustive set of use-cases; each application's needs will differ.)

Secondly, as mentioned above, an application may allow or deny any operation based on security checks. However, it must not alter (or "selectively report") filesystem information based on the results of the validation process (it's "all or nothing"). Said another way: at any given time, and for each virtual file or directory associated, an application must expose a single, consistent representation of the state of the file or directory to all processes accessing it. Here are some clarifying examples to help guide implementation:

  • A filesystem object cannot be reported as existent to process A, but as nonexistent to process B.
  • A filesystem object cannot be reported as a file to process A, but as a directory to process B.
  • A filesystem object's metadata, absent of any changes, must be reported consistently between requests; e.g., if a file's size is reported as 1 KB to process A, then it must also be reported as 1 KB to process B.
  • A file's contents, absent of any changes, must also be reported consistently between requests; e.g., for a file whose size is reported as 1 KB, the application must return exactly 1024 bytes when the file is read, and those 1024 bytes must be exactly the same (including ordering) regardless of which process is doing the reading.

 
 
Copyright (c) 2020 Callback Technologies, Inc. - All rights reserved.
CBFS Filter 2020 Java Edition - Version 20.0 [Build 7543]