Secure Coding Guidelines
Secure Coding Guidelines
www.atsec.com
a t s ec
in f or m ati on
s ec ur i ty
evaluation of the vulnerability patch development patch retrieval, assembly, and testing patch notification support for patch management issues downtime while applying the patch
Note that atsec does not advocate the specific secure SDLC methodology described.
2009 atsec information security corporation
Buffer overflow
A buffer overflow occurs when a program allows input to write data beyond allocated memory. The attacker can gain control over an entire application or crash a program by exploitation via buffer overflow. The most commonly-affected languages are C and C++. Some languages, like Java, C#, and Visual Basic, have an array bound checking mechanism and native string types, which generally prohibit direct memory access. Hence, these languages are less prone to buffer overflows. /** Example of Buffer Overflow **/ int main (int argc, char const *argv[]) { char buffer1[5] = "VXYZ"; char buffer2[5] = "PQRS"; strcpy(buffer2, argv[1]); printf("buffer1: %s, bufffer2: %s\n", buffer1, buffer2); return 0; } In the example, the argument is copied into buffer 2 without checking its size. This flaw introduces a buffer overflow vulnerability.
Integer overflow
An integer overflow takes place when the integer variable tries to store a larger value than the valid range as a result of an arithmetic operation [02]. C and C ++ are unsafe languages and are likely to turn an integer overflow into a buffer overflow. Some languages, such as Java and Ada, implement a rangecheck integer type, which significantly reduces the danger. /** Example of Integer Overflow **/ short int number = 0; char buffer[large_value]; while (number < MAX_NUM) { number += getInput(buffer+number); } In the example, the integer variable number may continuously create smaller values than MAX_NUM and would result in an integer overflow. This scenario will also overwrite MAX_Num-1 bytes of buffer.
2009 atsec information security corporation
Command injection
A command injection takes place when malicious data is embedded into input and is passed to the shell (or a language interpreter). As a result, the input is interpreted as some sort of command. Programs written in any language that fails to perform proper input validation could be vulnerable to these types of attacks. /** Example of Command Injection **/ int main(char* argc, char** argv) { char command[MAX] = "head "; strcat(command, argv[1]); system(command); }
In the example, the program executes the UNIX command head filename and displays the first 10 lines of a file which is entered as input. The strcat concatenates the command with filename and the system command executes it. Since there is no input validation, in this example the attacker can inject malicious command in input, e.g., hello.c; rm welcome.c. The execution of this program will display the first part of hello.c and delete the welcome.c file.
Cross-site scripting
A cross-site scripting (XSS) vulnerability is generally found in web applications in which an attacker enters malicious data in such a way that it will bypass access control mechanisms. As a result, the malicious data is reflected to the clients web browser (non-persistent XSS) or stored on the server side (persistent XSS), and can be responsible for stealing sensitive information, such as cookies (DOM-based XSS). By exploiting this vulnerability, the attacker can deface websites, perform phishing attacks, inject malicious links into trusted web pages, or send confidential information to other untrusted websites. If a proper means of server-side input validation is not implemented, then any language used for building web applications (for example, PHP, C#, VB.Net, ASP.NET, J2EE, and Active Server pages (ASPs)) is vulnerable to these types of attacks.
In the example, the code expects the name of a visitor to the web page as input and echoes it without input/output validation. This type of mistake could result in a cross-site scripting vulnerability.
An attacker can use .. / to jump from the current location to the target directory to access some important file/resource which he is not authorized to access.
Threat modeling
Threat modeling seeks to describe and develop the pertinent threats. The first step is to identify threats that might damage the application or product, and then to identify the vulnerabilities responsible for the threats. The next step includes analyzing the potential attacks caused by the threats and the planned control measures taken to mitigate the likelihood of such attacks.
The following table shows some system commands that could be used for hostile purposes [02]: Language C/C++ C/C++ Construct/Procedure System(), popen(),execlp(),execvp() _wsystem(), the ShellExecute() family of function System, exec Backticks Open Comment/Description Portable Operating System Interface (POSIX). Win32 only.
If called as one argument, and if the string has shell meta-characters, it can call the shell. Can call the shell. If the first or last character of the filename is a vertical bar, Perl opens a pipe instead. The rest of the filename is treated as data passed through a shell. Acts like a popen()call. Executes a string argument as Perl code. Evaluates a pattern-matched portion of a string argument as Perl code. Data gets evaluated as code. These assign to underlying POSIX calls. Takes data from file and gets evaluated as code. Similar to eval(). The intent of compiling text into code is to show that its going to get run. Java bytecode can be dynamically loaded and run. If called with an argument, it can explicitly invoke a shell. This procedure allows execution of any OS command.
Perl Perl Perl Python Python Python Python Python Java Java SQL
Vertical bar Eval Regular Expression/ e operator Exec, eval os.system, os.open Execfile Input Compile Class.forName(string), Class.newInstance(). Runtime.exec() xp_cmdshell
10
Penetration testing
A penetration tester performs black box testing to evaluate the security measures of the application. He has no knowledge of the source code or architecture of the application. A third-party pen-tester can conduct penetration testing. Results of this assessment process should be documented and presented to the concerned party.
Fuzz testing
Fuzz testing means testing the application against malformed data to see how it reacts. If the application fails, then a new bug should be reported and updated in the threat model. Every time the application is changed or updated, fuzz testing should be conducted. Fuzzing techniques use black box testing. It allows detection of most of the common vulnerabilities, for example, buffer overflow, cross-site scripting, and SQL injections.
11
General guidelines
Efficient input validation is mandatory. As mentioned in section 2, most vulnerabilities are the result of absent or inadequate input validation. Good practice suggests sanitizing every userentered input. Best practice is to create a white list of expected known good input parameters and formats, rather than relying on a black list of known bad inputs. Practicing sound software design and other phases of software engineering facilitates a structured, small, and simple code [08]. In addition, use a secure coding checklist. In order to track changes made to the code or document, use version/configuration control; this enables easy rollback to a previous version in case of a serious mistake. Version control facilitates accountability and saves development time. Never trust the input to SQL statements. Use parameterized SQL statements. Do not use string concatenation or string replacement to build SQL statements. Use libraries (e.g., anti-cross site scripting library) to protect against security bugs during web application development. Test the code with a web application scanner to detect vulnerabilities. Good practice also recommends use of the latest compilers, which often include defenses against coding errors; for example, GCC protects code from buffer overflows. As mentioned earlier, security design patterns can be used to tackle similar security-related concerns and provide solutions to known problems. It is good practice to code with proper error/exception handling. Check the return values of every function, especially security-related functions. Also, check for leakage of sensitive information to untrusted users. Make a security policy that prohibits the use of banned functions that make the code weak. Encourage a process of peer code reviews and sound security testing, as explained in the Software security testing section. Encode HTML input. Attackers use malicious input to conduct XSS types of attacks. Encoding of every user-supplied input can prevent the clients web browser from interpreting these as executable code. Do not store sensitive data in cookies. Encrypt all confidential data using strong cryptographic techniques. Handle key management carefully. Use a published and strong cryptographic algorithm with a sufficiently long key. Use of FIPS-approved cryptographic algorithms is encouraged. Do not use security protocols with inherent cryptographic weakness (e.g., SSL V2) and cryptographically weak random numbers. Using secure coding practices includes keeping informed about known and new vulnerabilities and software bugs by reading security-related forums, magazines, research papers, and newsletters. Every organization must educate its developers on how to write secure code, for example by offering a seminar or training session. The training should cover strategies and best practices to mitigate common threats. Additional emphasis should be given to the security features of programming languages and how to implement those features to build a secure application.
12
13
Do not invoke any of the following methods to execute using the immediate caller's ClassLoader instance. java.lang.Class.forName java.lang.Package.getPackage(s) java.lang.Runtime.load java.lang.Runtime.loadLibrary java.lang.System.load java.lang.System.loadLibrary java.sql.DriverManager.getConnection java.sql.DriverManager.getDriver(s) java.sql.DriverManager.deregisterDriver java.util.ResourceBundle.getBundle
The Java Virtual Machine performs language checks whenever an object accesses methods and fields. Using standard APIs (such as reflection API), access control rules can be bypassed. Be careful when using these APIs. Use char array or byte array instead of String() to store passwords: String() is immutable. Even if it is deleted, its object keeps floating in memory. Therefore, use char array or byte array instead of String and at the end of the method, use the following method to clear passwords and sensitive information.
14
/** Clear password **/ private void deletePassword(char[] password) { for (int i=0; i<password.length; i++) password[i]=' '; }
Be cautious when dealing with multiple threads [09]: If the code is using multithreading without proper synchronization, it is possible that all threads will manipulate the same data simultaneously, resulting in an unpredictable behavior of the program. Make sure that the code is synchronized to handle multiple processes. Organize code in such a way that one piece of data is manipulated by one thread at a time. Use semaphore to indicate data is ready for another threads consumption. Use the paint method for all your drawings, or use the paint method to set flags that indicate objects to be painted, and then use run loop to draw.
Enforce initialization of pointers to remove wild pointers. Once the memory is free, set the pointer to a null pointer or an invalid address. The developer can use tools mentioned in the following section to detect pointer-related dangers.
15
16
17
18