Secure coding

Last updated

Secure coding is the practice of developing computer software in a way that guards against the accidental introduction of security vulnerabilities. Defects, bugs and logic flaws are consistently the primary cause of commonly exploited software vulnerabilities. [1] Through the analysis of thousands of reported vulnerabilities, security professionals have discovered that most vulnerabilities stem from a relatively small number of common software programming errors. By identifying the insecure coding practices that lead to these errors and educating developers on secure alternatives, organizations can take proactive steps to help significantly reduce or eliminate vulnerabilities in software before deployment.

Contents

Buffer-overflow prevention

Buffer overflows, a common software security vulnerability, happen when a process tries to store data beyond a fixed-length buffer. For example, if there are 8 slots to store items in, there will be a problem if there is an attempt to store 9 items. In computer memory the overflowed data may overwrite data in the next location which can result in a security vulnerability (stack smashing) or program termination (segmentation fault). [1]

An example of a C program prone to a buffer overflow is

intvulnerable_function(char*large_user_input){chardst[SMALL];strcpy(dst,large_user_input);}

If the user input is larger than the destination buffer, a buffer overflow will occur. To fix this unsafe program, use strncpy to prevent a possible buffer overflow.

intsecure_function(char*user_input){chardst[BUF_SIZE];// copy a maximum of BUF_SIZE bytesstrncpy(dst,user_input,BUF_SIZE);}

Another secure alternative is to dynamically allocate memory on the heap using malloc.

char*secure_copy(char*src){size_tlen=strlen(src);char*dst=(char*)malloc(len+1);if(dst!=NULL){strncpy(dst,src,len);// append null terminator dst[len]='\0';}returndst;}

In the above code snippet, the program attempts to copy the contents of src into dst, while also checking the return value of malloc to ensure that enough memory was able to be allocated for the destination buffer.

Format-string attack prevention

A Format String Attack is when a malicious user supplies specific inputs that will eventually be entered as an argument to a function that performs formatting, such as printf(). The attack involves the adversary reading from or writing to the stack.

The C printf function writes output to stdout. If the parameter of the printf function is not properly formatted, several security bugs can be introduced. Below is a program that is vulnerable to a format string attack.

intvulnerable_print(char*malicious_input){printf(malicious_input);}

A malicious argument passed to the program could be “%s%s%s%s%s%s%s”, which can crash the program from improper memory reads.

Integer-overflow prevention

Integer overflow occurs when an arithmetic operation results in an integer too large to be represented within the available space. A program which does not properly check for integer overflow introduces potential software bugs and exploits.

Below is a function in C++ which attempts to confirm that the sum of x and y is less than or equal to a defined value MAX:

boolsumIsValid_flawed(unsignedintx,unsignedinty){unsignedintsum=x+y;returnsum<=MAX;}

The problem with the code is it does not check for integer overflow on the addition operation. If the sum of x and y is greater than the maximum possible value of an unsigned int, the addition operation will overflow and perhaps result in a value less than or equal to MAX, even though the sum of x and y is greater than MAX.

Below is a function which checks for overflow by confirming the sum is greater than or equal to both x and y. If the sum did overflow, the sum would be less than x or less than y.

boolsumIsValid_secure(unsignedintx,unsignedinty){unsignedintsum=x+y;returnsum>=x&&sum>=y&&sum<=MAX;}

See also

Related Research Articles

In information security and programming, a buffer overflow, or buffer overrun, is an anomaly where a program, while writing data to a buffer, overruns the buffer's boundary and overwrites adjacent memory locations.

In computer programming, an infinite loop is a sequence of instructions that, as written, will continue endlessly, unless an external intervention occurs. It may be intentional.

Defensive programming is a form of defensive design intended to ensure the continuing function of a piece of software under unforeseen circumstances. Defensive programming practices are often used where high availability, safety, or security is needed.

The C programming language provides many standard library functions for file input and output. These functions make up the bulk of the C standard library header <stdio.h>. The functionality descends from a "portable I/O package" written by Mike Lesk at Bell Labs in the early 1970s, and officially became part of the Unix operating system in Version 7.

Splint, short for Secure Programming Lint, is a programming tool for statically checking C programs for security vulnerabilities and coding mistakes. Formerly called LCLint, it is a modern version of the Unix lint tool.

The syntax of the C programming language is the set of rules governing writing of software in the language. It is designed to allow for programs that are extremely terse, have a close relationship with the resulting object code, and yet provide relatively high-level data abstraction. C was the first widely successful high-level language for portable operating-system development.

In computer programming, undefined behavior (UB) is the result of executing a program whose behavior is prescribed to be unpredictable, in the language specification to which the computer code adheres. This is different from unspecified behavior, for which the language specification does not prescribe a result, but defers to the documentation of another component of the platform.

Uncontrolled format string is a type of software vulnerability discovered around 1989 that can be used in security exploits. Originally thought harmless, format string exploits can be used to crash a program or to execute harmful code. The problem stems from the use of unchecked user input as the format string parameter in certain C functions that perform formatting, such as printf . A malicious user may use the %s and %x format tokens, among others, to print data from the call stack or possibly other locations in memory. One may also write arbitrary data to arbitrary locations using the %n format token, which commands printf and similar functions to write the number of bytes formatted to an address stored on the stack.

Code injection is the exploitation of a computer bug that is caused by processing invalid data. Injection is used by an attacker to introduce code into a vulnerable computer program and change the course of execution. The result of successful code injection can be disastrous, for example by allowing computer worms to propagate.

Secure by design, in software engineering, means that the software has been designed from the foundation to be secure. In such approach, the alternate security tactics and patterns are first thought; among them, the best are selected and enforced by the architecture design, and then used as guiding principles for developers. Secure by Design is more increasingly becoming the mainstream development approach to ensure security and privacy of software systems. In this approach, security is built in the system from the ground up and starts with a robust architecture design. Security architectural design decisions are often based on well-known security tactics, and patterns defined as reusable techniques for achieving specific quality concerns. Security tactics/patterns provide solutions for enforcing the necessary authentication, authorization, confidentiality, data integrity, privacy, accountability, availability, safety and non-repudiation requirements, even when the system is under attack. In order to ensure the security of a software system, not only it is important to design a robust security architecture (intended) but also it is necessary to preserve the (implemented) architecture during software evolution. Malicious practices are taken for granted and care is taken to minimize impact in anticipation of security vulnerabilities, when a security vulnerability is discovered or on invalid user input. Closely related is the practice of using "good" software design, such as domain-driven design or cloud native, as a way to increase security by reducing risk of vulnerability-opening mistakes—even though the design principles used were not originally conceived for security purposes.

In the C programming language, data types constitute the semantics and characteristics of storage of data elements. They are expressed in the language syntax in form of declarations for memory locations or variables. Data types also determine the types of operations or methods of processing of data elements.

The OpenBSD operating system focuses on security and the development of security features. According to author Michael W. Lucas, OpenBSD "is widely regarded as the most secure operating system available anywhere, under any licensing terms."

scanf format string refers to a control parameter used by a class of functions in the string-processing libraries of various programming languages. The format string specifies a method for reading a string into an arbitrary number of varied data type parameter(s). The input string is by default read from the standard input, but variants exist that read the input from other sources.

In the programming languages C and C++, the unary operator sizeof generates the size of an expression or a data type, measured in the number of char-sized storage units required for the type. Consequently, the construct sizeof (char) is guaranteed to be 1. The actual number of bits of type char is specified by the preprocessor macro CHAR_BIT, defined in the standard include file limits.h. On most modern systems this is eight bits. The result of sizeof has an unsigned integral type that is usually denoted by size_t.

A software code audit is a comprehensive analysis of source code in a programming project with the intent of discovering bugs, security breaches or violations of programming conventions. It is an integral part of the defensive programming paradigm, which attempts to reduce errors before the software is released. C and C++ source code is the most common code to be audited since many higher-level languages, such as Python, have fewer potentially vulnerable functions.

setjmp.h is a header defined in the C standard library to provide "non-local jumps": control flow that deviates from the usual subroutine call and return sequence. The complementary functions setjmp and longjmp provide this functionality.

In software, a stack buffer overflow or stack buffer overrun occurs when a program writes to a memory address on the program's call stack outside of the intended data structure, which is usually a fixed-length buffer. Stack buffer overflow bugs are caused when a program writes more data to a buffer located on the stack than what is actually allocated for that buffer. This almost always results in corruption of adjacent data on the stack, and in cases where the overflow was triggered by mistake, will often cause the program to crash or operate incorrectly. Stack buffer overflow is a type of the more general programming malfunction known as buffer overflow. Overfilling a buffer on the stack is more likely to derail program execution than overfilling a buffer on the heap because the stack contains the return addresses for all active function calls.

Increment and decrement operators are unary operators that add or subtract one, to or from their operand, respectively. They are commonly implemented in imperative programming languages. C-like languages feature two versions of each operator with slightly different semantics.

The write is one of the most basic routines provided by a Unix-like operating system kernel. It writes data from a buffer declared by the user to a given device, such as a file. This is the primary way to output data from a program by directly using a system call. The destination is identified by a numeric code. The data to be written, for instance a piece of text, is defined by a pointer and a size, given in number of bytes.

In the C programming language, operations can be performed on a bit level using bitwise operators.

References

  1. 1 2 Viega, John; Gary McGraw (2001). Building Secure Software: How to Avoid Security Problems the Right Way. MAddison-Wesley Professional. p. 528. ISBN   978-0201721522.