5 Security Considerations for Developers
This section provides information for developers about how they can create secure applications for Oracle Linux, and how to extend Oracle Linux to access external systems without compromising security.
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.
General Guidelines for Secure Coding
-
Check that input data is what the program expects by performing type, length, and bound checking. Inputs include command line arguments and environment variables in addition to data that a user enters.
-
Check input data for the inclusion of constructs such as shell commands, SQL statements, and any XML or HTML code that might be used in an injection attack.
-
Check the type, length, and bounds of arguments to system calls and library routines. If possible, use library routines that guard against buffer overflows.
-
Use full pathnames for file-name arguments, don't use files in world-writable directories, verify that a file being written to isn't a symbolic link, and protect against the unintended overwriting of existing files.
-
Check the type, length, and bounds of values returned by system calls and library routines. Make the code respond appropriately to any error codes that system calls and library functions set or return.
-
Don't assume the state of the shell environment. Check any settings that a program inherits from the shell, such as the user file-creation mask, signal handling, file descriptors, current working directory, and environment variables, especially
PATH
andIFS
. Reset the settings if needed. -
Perform assert checking on variables that can take a finite set of values.
-
Log any information about privileged actions and error conditions. Don't let the program dump a core file on an end-user system.
-
Don't echo passwords to the screen or send or store them as clear text. Before sending or storing a password, combine it with a salt value and use a secure one-way algorithm such as SHA-512 to create a hash.
-
If the program uses a pseudo random number generating routine, verify that the numbers that it generates are sufficiently random to match security requirements. Also use a good random seed that a potential attacker can't be expected to predict. See RFC 4086, Randomness Requirements for Security, for more information.
-
Enable Address Space Layout Randomization (ASLR) on the host system as this feature can help defeat certain types of buffer overflow attacks. See Address Space Layout Randomization.
-
When compiling and linking a program, use the Position Independent Executables (PIE) feature to generate a position-independent binary. See Position Independent Executables.
-
Consider using
chroot()
to confine the operating boundary of a program to a specified location within a file system. -
Don't run a shell command by calling
popen()
orsyscall()
from within a program, especially from asetuid
orsetgid
program.
setuid
or
setgid
bit set so that it can perform privileged actions on behalf of a
user who haven't been granted those privileges:
-
Don't set the
setuid
orsetgid
bit on shell scripts. However, if you use Perl scripts that aresetuid
orsetgid
, you can run perl in "taint mode," which can be more secure than using similar C code. See theperlsec(1)
manual page for details. -
Restrict the use of the privilege that
setuid
orsetgid
grants to the functionality that requires it, and then return the effective UID or GID to that of the user. If possible, perform the privileged functionality in its own monitored thread or process. -
Don't run a
setuid
orsetgid
program inside a child processes usingexeclp()
orexecvp()
, which use thePATH
environment variable.
General Guidelines for Network Programs
-
Perform a reverse lookup on an IP address to obtain the fully qualified domain name, and then use that domain name look up the IP address. Ensure that both IP addresses are identical.
-
Protect a service against Denial of Service (DoS) attacks by pausing the processing of requests if it becomes overloaded.
-
Set timeouts on read and write requests over the network.
-
Check the content, bounds, value, and type of data received over the network, and reject any data that doesn't conform to what the program expects.
-
Use certificates or preshared keys to authenticate the local and remote ends of the network connection.
-
Use encryption technology such as TLS or SSL to secure data sent over the network connection.
-
Wherever possible, use existing networking protocols and technologies whose security characteristics are widely understood.
-
Log any information about successful and unsuccessful connection attempts, data reception, and transmission errors, and changes to the service state.