Design Principles for Secure Coding
Follow these design principles to enhance security at the source code level:
- Least privilege
-
A process or user is granted only those privileges that are necessary to complete a task. User privileges are assigned according to their role, and all others are denied. To create a minimal protection domain, assign permissions when a process or thread requires them and removed after. This principle limits the potential damage that can result from attacks and user errors.
- Economy of mechanism
-
Keep the design straightforward so that fewer things can go wrong, fewer inconsistencies can emerge, and the code is easier to understand and debug.
- Complete mediation
-
Check every try to access to a resource, rather than only the first. For example, Linux checks access permissions when a process opens a file but not after. If a file's permissions change while a process has the file open, this can result in unauthorized access. Permissions could be checked whenever an open file is accessed but in practice, such checking is considered to be an unnecessary overhead because of the circumstances under which access was first obtained.
- Open design
-
Share the code's design or implementation. An open back door to a system is only as secure as the knowledge of its existence, so empowering others to help you find those back doors and close them before they're discovered is considered good security practice. This principle doesn't apply to information such as passwords or cryptographic keys, knowledge of which is best shared among as few people as possible. For that reason, many secure authentication schemes also rely on biometric identification or the possession of a physical artifact such a hardware token or smart card, in addition to knowledge of a PIN code or password.
- Separation of privilege
-
Divide the code into modules, where each module requires a specific, limited set of privileges to perform a specific task. You can require several privileges to grant access to a sensitive operation. This principle ensures separation of duty and provides defense in depth. For example, a main thread that has no privileges can generate a privileged thread to perform a task. A successful attack against the main thread would only gain minimal access to the system.
- Least common mechanism
-
Isolate users and their activities from each other. Users sharing processes or threads and information channels wouldn't be considered good security practice.
- Fail-safe defaults
-
Deny access to an operation by default. If a user without the necessary privileges tries to perform an operation it's denied and the system is still as secure as it was before the operation started.
- Accountability
-
Log the user and their privileges for each action that they try to perform. You can rotate and archive logs to avoid filling up a file system.
- Psychological acceptability
-
Select security mechanisms that are straightforward to install, configure, and use so that a user isn't tempted to try to bypass them.