Print Page      Email Page
< Back to Article List

Secure Coding Principles 101
By: Laura Taylor
January 20, 2004

Writing secure code is the first step in producing applications that are secure and robust. For custom applications that are already written, and commercial off-the-shelf (COTS) products, tools exist to audit for existing security deficiencies. Understanding the security vulnerabilities that exhibit themselves in existing products allows you to make better-informed decisions on patching and enables you to come up with other strategies to make these weak links in your infrastructure more secure.

Coding New Applications to Make Them Secure
Many security vulnerabilities could easily be prevented if security were taken into consideration at the beginning of the development process. While it is nearly impossible to come up with a list of every possible type of vulnerability that could come to exist as a result of coding oversights, it is possible to understand some of the more typical and common problems that often exhibit themselves as coding weaknesses and vulnerabilities.

When identifying coding weaknesses in applications, it is often the case that the same overlooked principles exhibit themselves time and time again. While you can't test your new application for every security vulnerability under the sun, you can in fact avoid the more common causes for security vulnerabilities to protect your new applications from the most obvious exploits.

Common Problems You Should Try to Avoid
By working to prevent some of the more overt security coding blunders, your chances of producing a secure application increases dramatically. Most of the typical security coding gaffes that you should try to avoid when coding in C, C++, Visual Basic, or any leading programming language can also be applied to JavaScript, Perl, and other scripting languages. Some of the most common security problems that you should try to avoid when writing new code or scripts are:

  • Weak file and group permissions
  • Race conditions
  • Buffer overflows
  • Problems with temporary files
  • Overly complex and unnecessary code
  • Insecure system calls and switches
  • Hard-coding passwords

  • According to Steve Bellovin, a renowned security researcher working at Bell Labs, "permission checking cannot be separated from access." What Mr. Bellovin means by that is that read, write, and execute permissions on programs play a deterministic role in what types of data users can access.

    Account and group ownership of various programs determine which users can run the programs, and which users can access the data that the programs use or produce. If a miscreant end-user has the ability to create confidential information using insecure programs, the confidential information could lack safeguards and has the potential to be exploited at some point in the future.

    Race conditions occur when the outcome of interrelated events depend on a particular event ordering sequence that cannot be guaranteed making the final state of the system unpredictable. A particular programming practice that can help prevent race conditions is to not start reading a file while it is still being written to by another process.

    Buffer overflows occur when hackers inject arbitrary code into assigned application buffer spaces causing unwanted executions of applications. Buffer overflows can be prevented by making sure that bounds checking is done on the length of input variables, arrays, and arguments.

    Certain applications create temporary files at the beginning of their execution for the purpose of being used later for parsing logging or other information. However, if the temporary file does not have secure permissions, it could be altered between the time it is created and the time the program later reads from it or writes to it again creating opportunities for exploitation.

    Overly complex code is much more difficult to secure. Always keep it simple. Keep in mind that in developing future versions of the application, or during bug fixes, developers who didn't initially write the code may be the ones trying to secure it. The more lines of code there are, the greater the probability that security vulnerabilities will be created.

    Using insecure switches or system calls can create opportunities for unauthorized users to exploit vulnerabilities. Some system calls spawn subroutines or shell commands that do not take into consideration secure path and environment variables that are used by the mother program. Insecure system calls may also inadvertently allow unauthorized read and write executions to be initiated. One safeguard against insecure system calls is to create a "sandbox," which encloses the child process or subroutine in a safe environment where it cannot be exploited.

    Hard-coding passwords into programs is probably the worst coding sin a developer can commit. Developers should never hard-code passwords into programs. If passwords are hard-coded into programs, it is possible that unauthorized users can discover them using sniffers or protocol analyzers.

    Code Weaknesses in Existing Applications; What Should You Do?
    Existing applications can be scanned for security vulnerabilities using a variety of industry-leading scanners. It's wise to scan your applications at least twice a year to find out if they have any exploitable weaknesses. Certain applications might be mission-critical and your management team may not let you uninstall them even if you discover that they have security vulnerabilities. However, there are things you can do to compensate for insecure code. First and foremost, you can check the vendor site, and the sites of third-party security vulnerability reporting centers, such as CERT to see if any security patches or fixes exist for the particular versions that you're running.

    Another good strategy to securing your existing applications is to harden the operating system they run. Hardening the operating system refers to making configuration changes to the underlying operating that will render it more secure and less vulnerable to attack. One way to tighten up the underlying operating system is to secure the TCP/IP stack on which your applications run. By securing the TCP/IP stack, you increase the resiliency of your applications making them less prone to buffer overflow and denial of service attacks. For leading operating systems, you can secure the stack by applying advanced security configurations, or by installing a stack-tightening tool such as SecureStack made by SecureWave.

    All operating systems can be hardened, and all of them should be if you want to optimize security. Hardening the operating system can decrease the ability that hackers have to take advantage of vulnerabilities in the applications that exist on top of the operating system. For example if you do not make sure that programs use secure file permissions and ownership credentials, it may be possible for hackers to exploit setuid or setgid files to gain unauthorized access.

    Products That Scan Applications and Operating Systems for Vulnerabilities
    Vendor Name Product Name Vendor Web Site
    eEye Retina
    ISS Internet Scanner
    Foundstone FS1000
    Sanctum, Inc. AppScan
    SpiDynamics WebInspect
    Qualys QualysGuard

    Security Policies for Writing Code
    Establishing and enforcing security policies for coding and scripting practices may not seem worth the time at first, however, the bigger your organization is the more important it is to do this. By establishing policies for secure coding practices, it establishes awareness about secure coding and indicates that your organization cares that any in-house, custom-developed applications are secure. You cannot enforce policies that don't exist, so establishing policies gives you recourse to take disciplinary action against developers or development managers that refuse to adhere to the established policies.

    Some application developers, particularly the ones with less experience, simply don't understand that security is something they should care about. By establishing specific policies that are particular to secure coding practices, novice developers become familiar with security principles before developing potentially insecure applications. Of course one the policies are establish developers need to be made aware of them.

    Security policies for secure coding and scripting could include policies such as the following:

  • Trusted programs or scripts should not invoke untrusted programs or scripts.
  • Do not use filenames when checking ownership and permissions within a script or program. Use filehandles instead.
  • When using input variables, arrays, and arguments, bounds checking should be established to prevent buffer overflows.
  • Sub-routines and sub-scripts should not inherit environment variables from other scripts or files.
  • All user-provided input should be checked for malicious code.
  • When scripting in Perl, taint mode should be turned on to prevent users from directly invoking system calls.
  • In Perl scripts when reading and writing to files, use advisory locks such as flock so that one routine or process does not corrupt the data of others.
  • All temporary files created by a program should be deleted when the temporary files are no longer needed.

  • These policies are just a start. There are many more policies that can be added to improve the security awareness and coding practices of your organization. Typically the organization that is responsible for securing network operations writes the security policies, but if your company is small, and you don't have a security team per se, a security savvy system administrator or software engineer can also write secure coding policies.

    A Word to the Wise
    As security awareness continues to grow, writing applications that are secure is becoming even more important. With a little diligence and awareness, any software engineer or developer can enhance their coding abilities (and career path) by learning basic, secure coding principles. After applications are developed, they should be tested and scanned for vulnerabilities before they are put on production servers. Some consulting firms specialize in doing code reviews, which may be well worth it if the application is going to be deployed at numerous sites on large enterprise networks.

    For Further Information
    For more information on secure coding principles and vulnerabilities in operating systems and applications, the following resources are well worth reading:

    Smashing the Stack for Fun and Profit
    By Aleph1

    Hardening the TCP/IP Stack to SYN Attacks
    By Mariusz Burdach

    Ostia: A Delegating Architecture for Secure System Call Interposition
    By Tal Garfinkel, Ben Pfaff, and Mendel Rosenblum

    Developing Secure Applications with Visual Basic
    By Davis Chapman
    ISBN: 0-672-31836-9

    Secure Coding: Principles and Practices
    By Mark Graff & Kenneth Van Wyck
    ISBN: 0-7356-1588-8

    Writing Secure Code
    By Michael Howard & David LeBlanc
    ISBN: 0-7356-1588-8

    DHTML Menu By Milonic JavaScript