Previous column

Next column

Secure Software

John D. McGregor, Clemson University and Luminary Software LLC, U.S.A.

space COLUMN

PDF Icon
PDF Version


Granting access to those who should have it and denying access to those who shouldn’t is a basic feature in many software products. Security is of strategic importance in many markets and types of products. In this month’s issue of Strategic Software Engineering, I will explore some issues about the strategic importance of security. I will discuss the influence of other product qualities such as correctness on the security of the product.


In January 2005, George Mason University found that hackers had gained access to a database containing. In February 2005, ChoicePoint, a data collection service, announced that a security breach threatened the personal information of over 145,000 people. And the list could go on. We want the software that manages our personal and professional data to be secure.

I recently attended the First Annual Cyber Security and Information Infrastructure Research (CSIIR) Workshop on Software Security held at Oak Ridge National Laboratory. As part of that workshop I made a presentation based on the following premise: Poorly written software will have more security vulnerabilities than well written software. In this issue I will expand on that topic with emphasis of the strategic importance of producing secure software products.

Notice that the title of this column is “secure software” as opposed to “software security.” That’s intentional. I am viewing this as the quality attribute of “being secure” rather than considering security features such as access control and data encryption. Taking this approach brings engineering processes to bear on the problem of how to achieve that or any other quality.

Software is secure when those who have authorization can use its functions and when those who do not have authorization can not. The secure quality attribute extends this definition to the data managed by the software. It is difficult to confine the achievement of security to a single application since its security usually depends upon the security of the operating system and utilities that provide essential services. Therefore, security is often defined as a quality of an entire environment – the platform and all applications running on that platform.

Obviously being secure, like any quality attribute, is more important in some products than others. Software that controls significant hardware, such as an airplane, or that manages significant data, such as banking information, will require much higher levels of security than software that controls an advertising sign or plays a game. However, a security vulnerability in a game running on a platform shared with software that performs secure business transactions may endanger those transactions.

McGraw makes the very good point that much of the software security work deals with operational level fixes, such as firewalls, because they were designed by operational level people [McGraw 04]. That is too late. The secure quality needs to be a part of the engineering process from product inception. I will discuss how to incorporate security as a quality consideration early in the development life cycle.


There is growing support for developing secure software by focusing on software engineering best practices. I will review some of that support so that you can understand the range of responses to the secure software problem. In succeeding sections, I will consider several aspects of the software engineering approach in the context of that support.

The Security Across the Software Development Lifecycle Task Force led by co-chairs Ron Moritz of Computer Associates, and Scott Charney of Microsoft made a number of recommendations about improving software development techniques that will in turn improve the security of the software being produced [Moritz 04]. Included in those recommendations are:

  • Adopt software development processes that can measurably reduce software specification, design and implementation defects.
  • Software producers should adopt practices for developing secure software.
  • Software producers, where appropriate, should conduct measured trials of available approaches and publish their results.

I will discuss some actions that follow the first two recommendations.

Gary McGraw in his “Building Security In” department in IEEE’s Security and Privacy describes the “trinity of trouble. [McGraw 04]” These are three problems that contribute to increasing security problems. They are:

  • Ubiquitous network connections
  • Easily extensible systems
  • Increasingly complex systems

The latter two problems are clearly software engineering issues and I will address these shortly. McGraw’s department has presented a number of articles that relate to a software engineering approach to secure software.

What makes secure software strategic to a company? It’s the strategic risk of losing the trust of your customers as well as the more immediate risk of litigation. There are several ways to mitigate these risks. In the next section I will discuss qualities of software products that reduce the probability of security problems and in the following section I will discuss some techniques for achieving those qualities.


Talking about “well written” software, as I did in my premise, is too vague for engineering analysis. In this section I will examine specific qualities and their relationship to being secure. Almost any specified quality that is not achieved by the product could degrade the secure quality and introduce a security vulnerability. However, certain qualities speak directly to the resistance of a product to attack.


Correctness is a quality that is often implicitly required rather than explicitly specified. For our purposes, correctness is the ability of a software product to satisfy its functional requirements. Security is often compromised by the mistaken idea that a formal proof of the specification results in correctness. A proof is only a first step. In fact some of the most prevalent security vulnerabilities arise from either an incomplete specification or a failure to implement the specification exactly as stated.

Buffer overflow errors account for a large percentage of vulnerabilities. So called “complete” specifications often consider only static qualities and do not specify operational characteristics such as maximum size of a data structure or how overflows will be handled.

The specification being complete and correct are not sufficient to guarantee the product is correct if the implementation of that specification is created by a human. Automatic program generation is similarly flawed unless the generator has been proven correct.

If the program is not correct then it becomes difficult to know whether the program’s failure to meet expectations is due to a security breach or just built-in incorrectness.


The percentage of time that a product can continue to function in the face of unusual conditions is the measure of robustness. Notice that I did not say function correctly. The specification often does not indicate what happens in the case of unexpected errors in which case there is no definition of “correct.” Engineers must apply a “reasonableness” criteria when evaluating robustness. That is, is the product’s response to unusual events reasonable?

Embedded systems are often implemented to be robust – it is not acceptable to have your car reboot on the highway - by having an error state in which the system is specified to perform some function that will do the least harm to the hardware or the environment. This function is often a transition back to the initial state but it may be a transition to some other intermediate, but stable, state. Any input that is not covered by the specification results in the system entering that error state.

The software is most vulnerable in those regions of input where there is no specification. Malicious attacks are often probes to find the boundaries of a specification. Once this limit is established, data is supplied that stresses the system looking for areas in which the software is not robust.

Robustness is achieved by allowing for “other” cases at every opportunity. That is, the design should anticipate that not all cases are covered by the specification.


The reliability of a product is measured by the percentage of the operating time that the product performs requested functions correctly. Software is vulnerable when there are specified inputs for which the product does not produce correct results. The user of the product, or other products that consume that product’s output, may perform incorrectly due to the incorrect output. The more unreliable the software the more vulnerable the software.

Reliability is a property of individual components and it is an emergent property of an assembly of components. When the faults causing the software to fail is a result of the composition the vulnerability is particularly difficult to recognize. It can not be found during unit testing and may be so narrow that finding it during system testing is also unlikely.

Quality assurance activities such as conducting active design reviews, establishing and checking compliance with design and coding standards, and testing the product code contribute to the reliability of the resulting product.


I will briefly address McGraw’s trinity of trouble, or at least two of the three problems. Then I will talk about some necessary actions.


McGraw’s concern, as I understand it, is that as software is designed to be extensible, holes are created that are vulnerable to attack. On the other hand Fredrick Sheldon of Oak Ridge National Laboratory is concerned with “How do we engineer software in a way that makes the software malleable (extensible) with respect to security context changes?” [Sheldon 05]. Both concerns are valid and must be accommodated - somehow.

Extensibility mechanisms differ in their binding times. Designs that use inheritance for extensibility bind choices at design time while architectures such as the Eclipse plug-in architecture bind choices at execution time. The technique for making each of these extension points secure will vary with the binding time. Some techniques already exist. Java reflection allows access to the inheritance hierarchy but the policy files that allow the specification of permissions can be used to thwart certain types of access. This is definitely an area for further research.


The concern here is that as software products are becoming more and more complex, security vulnerabilities will be more likely to exist and to be hidden from the usual testing. This is really no different than the problems that many software development efforts are facing as they attempt to achieve a wide range of qualities.

My reaction to complexity is usually to decompose it away. The key is to start small and grow as the product comes together. By this I mean begin with the basic units - components, classes, functions, or whatever that are being used as the building blocks. Apply the appropriate techniques to these units to achieve the required level of quality. Then as units are integrated, again apply the appropriate techniques to assure that the assembly has the desired level of quality. Repeat as assemblies are assembled into still larger assemblies.

This technique doesn’t eliminate complexity from the product, but it does address a major risk. That risk is the possibility that the assembly of two secure components is not a secure assembly. Emergent behaviors that result from the assembly, and are not observable in the individual components, can introduce vulnerabilities. By recursively applying reviews and tests for the secure quality as the assemblies grow, take advantage of previous work but does not assume that the newly created assembly is also secure.

Consistent error handling

A large number of vulnerabilities are exploited by causing an error and taking advantage of how the error is handled. The best strategy is to bullet-proof the software so that errors don’t happen but none of us is perfect so we have to anticipate errors. Therefore, the alternative strategy is to provide a consistent error handling scheme. The expectation is engineers will be less likely to make mistakes in the presence of a consistent error handling scheme.

I will not go into a comparison of returning error codes versus exceptions here. The point to be made here is that the error handling needs to be visible at the appropriate design level. Error mechanisms that will be propagated between functions but within the component must be visible in the function-level specifications within the component. Error mechanisms that will be propagated between components need to be explicit and public in the component’s specification and recognized in the architecture.

Robust data structures

As I said above the best defense is to bullet proof the software. Buffer overflows are a leading source of vulnerability. One of the participants in the CSIIR workshop made the excellent point that you can’t overflow a hardware buffer. Why should it be different with a software buffer? There are widely-used practices that can prevent overflows but too often they are not followed.

What is the acceptable behavior when new data is available and there is no room for it in the existing buffer? The possible answers are:

  • Standard approach – continue as usual, runoff the end, reference random memory, cause wild and crazy things to happen in your program
  • Not so standard approach – do nothing, don’t write the data, it will eventually be lost
  • Throw a specified exception – allow others to handle
  • Expand buffer to accommodate, after checking that there really is more memory

Obviously, the first two approaches are not acceptable but the first one is widely used. The last two approaches are not mutually exclusive. Taken together they form an implementation pattern (different from a language idiom and more detailed than a design pattern). Figure 1 shows the decision tree for the implementation. Different languages will require different language idioms.

Figure 1 - Buffer overflow implementation pattern

While I have focused on the buffer overflow problem for obvious reasons, the same detailed analysis should be done for every state that is maintained in a product.

Misuse and Abuse case

Software engineering provides techniques to build a product to a purpose. The use case technique has proven an effective technique for capturing the thinking of stakeholders about how the product will be used [Jacobson 92]. Change cases are a type of use case that capture how stakeholders think the product will change [Ecklund 96].

Several authors describe misuse and abuse cases as an approach to helping stakeholders think about possible scenarios that need to be defended against [Hope 04]. This includes defining actors that model attackers and brain storming how the attackers would “use” the system. These abuse cases can be built on known attack patterns. The report of the Security Across the Software Development Lifecycle Task Force included a list of 49 such patterns. Table 1 shows a few of their attack patterns.

Use a User-Supplied Configuration File to Run Commands That Elevate Privilege
Make Use of Configuration File Search Paths
Direct Access to Executable Files
Embedding Scripts within Scripts
Leverage Executable Code in Non-executable Files
Argument Injection

Table 1 - Attack patterns

Our use case template includes multiple scenarios that describe how the actor uses the product. We include “sunny day,” alternative, and exceptional scenarios. Misuse scenarios can also be included in the standard use cases. These differ from the ones that accompany an attack actor in that these may be accidental situations initiated by an innocent, careless user.

Plan of action

Building secure software requires the same techniques as building reliable software or modifiable software. The attribute-driven design approach (ADD) [Bass 00] calls for several items:

  • A clear definition of the quality attribute
  • A framework for reasoning about the quality
  • A set of architectural tactics that enhance the quality

At the workshop I proposed an agenda for research to expand the range of techniques available for engineering security. The items on the agenda are:

Develop method engineering tactics and guidelines that enhance the security quality of the software through improved processes.

Structure architecture evaluation techniques to focus on security by searching for static security patterns.

Discover and capture test patterns that correspond to dynamic security patterns.

Develop focused test techniques to effectively explore security test patterns while reducing the test suite size.

Create a defect model for security that can be used to predict types and number of security vulnerabilities in scientific codes.

Execution of these actions would add to the set of tactics that are currently available for engineering secure software.

At the workshop, Professor Ali Mili summed up what I and others were saying, ôSecurity cannot be achieved by focusing on vulnerabilities, no more than reliability can be achieved by focusing on faults, as vulnerabilities may have widely varying impacts on security, just as faults are known to have widely varying impacts on reliability. Rather, security should be managed by pursuing a policy that targets the highest impact vulnerabilities first. In light of this observation, we argue in favor of shifting our focus from vulnerability avoidance / removal / detection to measurable security attributes.


I have discussed some of the things that are being done to engineer secure software. I believe there is much more that can be done and I have provided an initial agenda. Many good ideas were advanced at the workshop.

Security is a quality like any other non-functional requirement. It must be engineered into the product rather than being added on at the last minute. It can also be subject to tradeoff with other more important qualities – security versus testability for example. It can also be a point of variation in a product line architecture - products that are secure and products that are not.

Security becomes more important as more of our personal and business data is computerized. The secure quality attribute has to be as carefully engineered as every other quality upon which our strategic goals depend.



Thanks to Fredrick Sheldon for comments on an earlier version of this and to all the attendees of the First Annual Cyber Security and Information Infrastructure Research (CSIIR) Workshop on Software Security for the discussions.


[Bass 00] Felix Bachmann; Len Bass; Gary Chastek; Patrick Donohoe; and F. Peruzzi. The Architecture Based Design Method (CMU/SEI-2000-TR-001, ADA37581). Pittsburgh, PA: Software Engineering Institute, Carnegie Mellon University, 2000

[Ecklund 96] Earl F. Ecklund, Lois M.L. Delcambre, and Michael J. Freiling. Change Cases: Use cases that identify future requirements. Proceedings of the Eleventh Conference on Object-Oriented Programming Systems, Languages, and Applications, Association for Computing Machinery, 1996.

[Hope 04] Paco Hope, Gary McGraw, and Annie I. Anton. Misuse and Abuse Cases: Getting Past the Positive, IEEE Security and Privacy, IEEE Computer Society, 2004.

[Jacobson 92] Ivar Jacobson, Magnus Christerson, Patrik Jonsson, and Gunnar Overgaard. Object-Oriented Software Engineering, Addison-Wesley, reading, Massachusetts, 1992.

[McGraw 04] Gary McGraw. Software Security, IEEE Security & Privacy, IEEE Computer Society, 2004.

[Mili 05] Ali Mili. Personal communication, 2005.

[Moritz 04] Ron Moritz and Scott Charney. Improving Security Across the Software Development Life Cycle, Security Across the Software Development Lifecycle Task Force, 2004.

[Sheldon 05] Fredrick Sheldon. Personal communication, 2005.

About the author

Dr. John D. McGregor is an associate professor of computer science at Clemson University and a partner in Luminary Software, a software engineering consulting firm. His research interests include software product lines and component-base software engineering. His latest book is A Practical Guide to Testing Object-Oriented Software (Addison-Wesley 2001). Contact him at

Cite this column as follows: John McGregor: “Secure Software", in Journal of Object Technology, vol. 4, no. 4, May-June 2005, pp. 33-42

Previous column

Next column