BUY THIS BOOK
Add to Cart

PDF $23.99

Safari Books Online

What is this?

Looking to Reprint or License this content?


Secure Coding: Principles and Practices
Secure Coding: Principles and Practices

By Mark G. Graff, Kenneth R. van Wyk

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: No Straight Thing
Out of the crooked timber of humanity, no straight thing can ever be made.
—Immanuel Kant
In late 1996 there were approximately 14,000,000 computers connected to the Internet. Nearly all of them relied on the Transmission Control Protocol (TCP), one of the fundamental rule sets underlying communication between computers, and the one used for most common services on the Internet. And although it was known to have security weaknesses, the protocol had been doing its work quietly for nearly two decades without a major attack against it.
But on September 1 of that year, the online magazine Phrack published the source code for a network attack tool that exploited the trusting way the protocol handled connection requests (see the sidebar A Fractured Dialogue). Suddenly, the majority of those 14,000,000 computers were now vulnerable to being taken offline—in some cases, crashed—at the whim of any malcontent capable of compiling the attack program.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Vulnerability Cycle
Let's consider for a moment an all-too-common sequence of events in today's security world. (Figure 1-2 illustrates it graphically.)
  1. Someone uncovers and discloses a new vulnerability in a piece of software.
  2. Bad guys quickly analyze the information and use the vulnerability to launch attacks against systems or networks.
  3. Simultaneously, good guys (we'll include security folks who work for the vendor) start looking for a fix. They rally software development engineers in their respective organizations to analyze the vulnerability, develop a fix, test the fix in a controlled environment, and release the fix to the community of users who rely on the software.
  4. If the vulnerability is serious, or the attacks are dramatic, the various media make sure that the public knows that a new battle is underway. The software developers at the organization that produced the product (and the vulnerability!) are deluged with phone calls from the media, wanting to find out what is going on.
  5. Lots of folks get very worried. Pundits, cranks, finger-pointers, and copycats do their thing.
  6. If a knee-jerk countermeasure is available and might do some good, we'll see a lot of it. (For example, CIOs may direct that all email coming into an enterprise be shut off.) More often than not, this type of countermeasure results in numerous and costly business interruptions at companies that rely on the software for conducting their business operations.
  7. When a patch is ready, technically oriented folks who pay close attention to such matters obtain, test, and apply the patch. Everyday system administrators and ordinary business folks may get the word and follow through as well. Perhaps, for a lucky few, the patch will be installed as part of an automated update feature. But inevitably, many affected systems and networks will never be patched during the lifetime of the vulnerability—or will only receive the patch as part of a major version upgrade.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
What Is an Attack?
In a general sense, an attack on a system is any maliciously intended act against a system or a population of systems. There are two very important concepts in this definition that are worth pointing out. First, we only say that the act is performed with malicious intent, without specifying any goals or objectives. Second, some attacks are directed at a particular system, while others have no particular target or victim. Let's look at these concepts and terms one by one:
Goals
The immediate goal of an attack can vary considerably. Most often, though, an attack goal is to damage or otherwise hurt the target, which may include stealing money, services, and so on.
Subgoals
Achieving one or more of the goals above may require first reaching a subgoal, such as being granted elevated privileges or authorizations on the system.
Activities
The activities that an attacker engages in are the things that he does that could help him achieve one or more of his subgoals. These could include using stolen login credentials (e.g., username and password); masquerading as a different computer, user, or device; flooding a network with malformed packets; and so on.
Events
The activities mentioned above may result in attack events—improper access could be granted, request processing could be suspended, storage space could be exhausted, or a system or program could be halted.
Consequences
A further concept, often confused with an attack event, is the business consequence. By this term we mean the direct result of the events, such as financial balance sheets being incorrect, or a computer system being unavailable for a business process.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Why Good People Write Bad Code
Now that we've walked on the dark side, looking at all kinds of things that can go wrong with our software, let's turn our attention back to root causes: why do software flaws occur? Why do good people write bad code?
A great many people believe that vulnerabilities are the spawn of stupid (and probably slothful) programmers. Some adherents to this credo have been customers of ours. Although we have listened respectfully to the arguments for many hours, we disagree.
We believe that, by and large, programmers want to write good software. They surely don't set out with the intention of putting security flaws in their code. Furthermore, because it's possible for a program to satisfy a stringent functional specification and nevertheless bring a vulnerability to life, many (if not most) such flaws have been coded up by people who do their best and are satisfied with (even rewarded for) the result.
What's so hard about writing secure code? Why do vulnerabilities exist at all, let alone persist for decades? Why can't the vendors get it right?
We believe there are three sets of factors that work against secure coding:
Technical factors
The underlying complexity of the task itself
Psychological factors
The "mental models," for example, that make it hard for human beings to design and implement secure software
Real-world factors
Economic and other social factors that work against security quality
This is a hard problem. After a close look at our examples, we think you will come to agree that wiping out security vulnerabilities by just doing a better job of coding is a monumental—perhaps hopeless—task. Improved coding is critical to progress, of course. But some vulnerabilities seem to arise without any direct human help at all. We engineers will have to adapt our tools and systems, our methods, and our ways of thinking. Beyond this, our companies, our institutions, and our networked society itself will need to face up to the danger before this scourge can pass away.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
A Call to Arms
You probably knew that the security of Internet software was a mess before you started this book. How do we extricate ourselves?
In addition to advocating the widespread adoption of the techniques and practices described in this book, we also call for advances in three particular areas: education, standards, and metrics.
Education
Clearly, we must do a better job of educating engineers about the principles and techniques of secure coding.
We must also ensure that the public understands the demonstrably poor security of Internet software today, and that the various facets of government comprehend the magnitude of the disasters that can strike us if we don't make drastic improvements.
We also need to convince the press that those who attack systems are not geniuses; they're merely criminals. It would help, too, if the media would stop publicizing dramatic names for the various vulnerabilities and exploitation programs, such as (to invent an example) the "Red Slammer." Will it take a decade or more of severe or deadly incidents to change public attitudes about computer attackers?
Standards
Many people have compared the software vulnerability situation today to the carnage endured before the advent of mandatory seat belts in private automobiles.
Having reached the point where we agree, we now call for the development of true secure coding standards—standards that can be used by companies, governments, and consumers to promote prosperity and ensure our safety. It is the only way we can see to get software vendors to invest in quality. If every company is forced to participate, none will be able to make the excuse that they can't afford to divert resources from more competitive pursuits.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Summary
In this first chapter, we hope we've challenged you with some new ideas about security vulnerabilities. We particularly hope that you may now consider that the blame for security vulnerabilities belongs, to some degree, to all of us who buy and use the seriously flawed programs available today.
This point of view does not minimize or try to mitigate the responsibility of software producers for security quality. They should be held to the highest standards and hung out to dry if they fail. But it does in fact "take two to tango," and customers (particularly, the U.S. government, the biggest software customer, so far as we know, in the world) bear some responsibility to demand secure software.
Those among us who produce software, of course, have a special responsibility and a unique opportunity to improve matters. Our discipline has not reached the state of understanding and sound practice exemplified by those bridge builders shown on the cover of this book, but the folks driving their virtual vehicles over our structures rely on us nevertheless to keep them safe.
In Chapter 2, we'll exhibit the most important architectural principles and engineering concepts you can employ to make your software as secure as possible. In that chapter, we'll try to pass along some distilled security wisdom from the generation of coders that built the Internet.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Architecture
Architecture is easy: you just stare at the paper until droplets of blood appear on your forehead.
—Unknown
Imagine with us that you are the engineering director of a large company and you are interviewing candidates for a position as your software security architect. You ask the three main candidates, "Just how secure will you be able to make my software?"
If one of the candidates answers, "I can make your software secure against any attack," we hope you'll show him the door. If another candidate answers, "I will make your software as secure as it can possibly be," we hope you'll give her a failing grade as well.
In our opinion, the winning response is, "How secure do you want it to be?" That's because designing in too much security drains away resources, frustrates people, and can complicate matters so much that intelligent software maintenance is impeded. Superfluous security controls can actually diminish the overall safety of an enterprise.
The process of selecting design elements and principles to match a defined security need is what we mean by security architecture. In this chapter, we'll examine the role of architecture and how it applies throughout the development process, and we'll introduce the security engineering principles we believe are key to the development of secure software. Finally, at the end of the chapter, we'll discuss how some of these ideas were not followed in the design of the TCP stack with regard to our SYN flood example. (Many of our points, as you will see, apply to any complex human enterprise.)
Returning to our interview example for a moment, what would your answer be to the question, "How secure do you want it to be?" Our suggested answer is, "Just secure enough." Throughout this book, we'll help you figure out what that would mean for your company. We also aim to teach you how to select, from many possible technical solutions, a set of complementary tools and procedures to ensure that your software is just that secure.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
What Is Security Architecture?
Although the concept is somewhat abstract, there are several reasonable definitions. We think of security architecture as a body of high-level design principles and decisions that allow a programmer to say "Yes" with confidence and "No" with certainty.
Let's look at an example. Suppose that you are responsible for your company's main e-commerce application. If you are asked to modify it so that it can be operated on a server outside your firewall by an "application service provider," you could agree—knowing that you won't be compromising security—if your architecture provides for sound and flexible third-party authentication and authorization. If the vice president of operations asks you if thieves could use your application to break through the corporate firewall, you can rule out that possibility if your architecture constrains tightly enough the access granted to your software as it runs.
A security architecture also serves as a framework for secure design, which embodies in microcosm the four classic stages of information security: protect, deter, detect, and react.
There is still another way to look at it. We know many professionals who, if asked for an example of a "security architecture," would produce a set of documents. We have no problem with that definition, either, as we'll describe in the next section.
Whichever way you think of it, one thing is sure. A good security architecture can be applied many times, to many applications. There is no need to "reinvent" the entire framework every time you or someone else starts a new program. Many large well-run development shops we have seen use a sound, well-thought-out architecture as the foundation for all their development. Individual designs are based on it, derive principles and rules from it, and occasionally depart from it.
Finally, we'll point out one thing that security architecture is not. Architecture is different from policy. Your site should certainly have a set of security policies and standards, laying rules about who can have access to what kinds of data, the testing procedures necessary for an application to be certified to run on the network, and so on. Such decisions should be developed in the usual way that policy is formulated for your enterprise, and then used as a guideline for your application architecture.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Principles of Security Architecture
We've defined 30 basic principles of security architecture:
  1. Start by asking questions
  2. Select a destination before stepping on the gas
  3. Decide how much security is "just enough"
  4. Employ standard engineering techniques
  5. Identify your assumptions
  6. Engineer security in from day one
  7. Design with the enemy in mind
  8. Understand and respect the chain of trust
  9. Be stingy with privileges
  10. Test any proposed action against policy
  11. Build in appropriate levels of fault tolerance
  12. Address error-handling issues appropriately
  13. Degrade gracefully
  14. Fail safely
  15. Choose safe default actions and values
  16. Stay on the simple side
  17. Modularize thoroughly
  18. Don't rely on obfuscation
  19. Maintain minimal retained state
  20. Adopt practical measures users can live with
  21. Make sure some individual is accountable
  22. Self-limit program consumption of resources
  23. Make sure it's possible to reconstruct events
  24. Eliminate "weak links"
  25. Build in multiple layers of defense
  26. Treat an application as a holistic whole
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Case Study: The Java Sandbox
An excellent example of a system that was intended from scratch to be secure is the Java "sandbox." Java certainly has had its share of security vulnerabilities. But it remains an excellent example of the principle that many mistakes can be designed out at by selecting an appropriate security model.
Let's let the chief security architect of Java, Sun's Li Gong, explain the idea of the sandbox:
The original security model provided by the Java platform is known as the sandbox model, which [provided] a very restricted environment in which to run untrusted code obtained from the open network... [L]ocal code is trusted to have full access to vital system resources (such as the filesystem) while downloaded remote code (an applet) is not trusted and can access only the limited resources provided inside the sandbox...
Overall security is enforced through a number of mechanisms. First of all, the language is designed to be type-safe and easy to use. The hope is that the burden on the programmer is such that the likelihood of making subtle mistakes is lessened compared with using other programming languages such as C or C++. Language features such as automatic memory management, garbage collection, and range checking on strings and arrays are examples of how the language helps the programmer to write safe code.
Second, compilers and a bytecode verifier ensure that only legitimate Java bytecodes are executed. The bytecode verifier, together with the Java Virtual Machine, guarantees language safety at run time...
Finally, access to crucial system resources is mediated by the Java Virtual Machine and is checked in advance by a SecurityManager class that restricts the actions of a piece of untrusted code to the bare minimum.
Now, as it happens, Mark can add a personal footnote about the Java sandbox. We include it as a cautionary tale, with the caveat that we are relying on his recollections for the accuracy of the story. (The sense of it is certainly right.)
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Summary
In this chapter, we presented what we consider to be the fundamentals of secure application architecture. These are the principles that you will constantly call on with confidence in deciding what design decisions to make and how to implement your application. As you read through them, you probably noticed that many of the principles are applicable not only to secure design, but also to many aspects of software design and implementation.
By way of example, let's consider defense in depth once again. This principle is used in designing a secure network infrastructure, a bank vault, a military compound, and all kinds of other things. In this book we'll naturally be concentrating on how it applies to designing, implementing, and deploying an application. But remember that a good architectural principle should be broadly applicable.
Returning to our discussion of the SYN flood attacks, we feel that, at a minimum, the following architectural principles were violated (or at least not sufficiently followed) in the TCP stack design:
  • Design with the enemy in mind
  • Build in appropriate levels of fault tolerance
  • Degrade gracefully
  • Self-limit program consumption of resources
We'll discuss each of these in more detail in Chapter 3 when we talk about the specific design flaws of the TCP stack, but our point here is that adherence to each of these principles would have—or at least could have—resulted in a very different design (and thus implementation) of the TCP stack.
Most technologists probably consider our architectural principles to be just plain common sense. They're right and they're wrong. While these principles do represent sound security practices, they're far too often overlooked—or implemented as an afterthought—in designing software that should be secure.
Our final message here is that we feel that software security should be so ingrained in an application and its surrounding architecture that it becomes a business enabler. By starting with the architectural principles that we've presented here, businesses should be able to enable practices and processes with confidence that they would otherwise run screaming from. Imagine a commercial enterprise that enables its employees, contractors, and temporary employees to sit down at any workstation in the company and get to their files and do productive work, just as if they were logged into their own workstations—and to do it anywhere, whether at home or at a mall kiosk. Imagine the cost savings that they could gain from that.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Design
I don't know what effect these men will have on the enemy, but, by God, they frighten me.
—The Duke of Wellington, on replacements sent to him in Spain
Good design is the sword and shield of the security-conscious developer. Sound design defends your applications from subversion or misuse, protecting your network and the information on it from internal and external attacks alike. It also provides a safe foundation for future extensions and maintenance of the software.
Bad design makes life easier for attackers and harder for the good guys, especially if it contributes to a false sense of security while obscuring pertinent failings.
Think about the designers of the TCP protocol. They made mistakes that resulted in a great deal of heartache, because they did not adequately understand their potential adversaries. They (and, later, the implementers as well) did an admirable job of making software that properly executed the relevant Internet Requests for Comments (RFCs) that defined the protocol. But they did not adequately consider what would happen when a remote system behaved dishonorably, with the deliberate intent of not following the RFCs. SYN flood attacks were the result. Attackers cheat!
Where does good design come from? How can you make good design decisions and avoid bad ones? This chapter shows you how to make secure design decisions.
There is no question that resolving security issues during the design phase of software is ideal from a developer's point of view. Our experience (confirmed by recent academic studies) shows that investing in design also makes good business sense. To make this principle more tangible, let's try to calculate the cost to fix a security shortcoming at design time—as opposed to doing it as part of implementation, during testing, or via a software patch. Research reveals the following ratios, illustrated by Figure 3-1:
  • If the cost at design time is taken as a unit of 1, the cost of fixing the same bug in implementation is about 6.5 times as great.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Why Does Good Design Matter?
There is no question that resolving security issues during the design phase of software is ideal from a developer's point of view. Our experience (confirmed by recent academic studies) shows that investing in design also makes good business sense. To make this principle more tangible, let's try to calculate the cost to fix a security shortcoming at design time—as opposed to doing it as part of implementation, during testing, or via a software patch. Research reveals the following ratios, illustrated by Figure 3-1:
  • If the cost at design time is taken as a unit of 1, the cost of fixing the same bug in implementation is about 6.5 times as great.
  • If the security vulnerability is caught at testing time, the cost is 15 times as great.
  • If the security vulnerability has to be patched after the software is released—which means that the fix itself will have to be released as a patch—the cost is about 60 times what it would have cost to fix the problem at the design stage.
Figure 3-1: Cost of fixing security flaws during different development phases
These figures argue strongly the case for being careful during design. Keep in mind, too, that, as the study we just cited points out, there are intangible costs as well: loss of goodwill, reputation, and functionality, and more stress for everyone involved in the project are common outcomes.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Secure Design Steps
There is so much more to security design than planning out a modularized application with minimal privilege. So, how do we get where we want to go? Although there are many differing software development processes, security design efforts typically include most of the following specific steps, and ask the following specific questions:
  1. Assess the risks and threats:
    What bad thing can happen?
    What are the legal requirements?
  2. Adopt a risk mitigation strategy:
    What is our plan?
  3. Construct one or more mental models (e.g., a "bathtub," a "safe," a "jail," a "train") to facilitate development:
    What does it do?
  4. Settle high-level technical issues such as stateful versus stateless operation, use of privileges, or special access by the software:
    How does it work?
  5. Select a set of security techniques and technologies (good practices) to satisfy each requirement:
    What specific technical measures should we take?
  6. Resolve any operational issues such as user account administration and database backup (and the protection of the resulting media):
    How will we keep this application system operating securely?
The following sections cover the first five of these steps; Chapter 4 and Chapter 5 describe the final step from different perspectives.
Here we present an informal way of working that has sufficed for our purposes for many years. There are plans available for integrating security into development that are much more structured. We summarize the best in Chapter 6 and provide additional pointers in Appendix A.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Special Design Issues
Apart from the security design process that we've outlined previously, there are several additional design issues that you're likely to face.
Although we have concentrated so far on how you can enhance security in an application as you develop it, we do not mean to imply that without access to source code you are powerless. In fact, several significant security techniques can be applied to existing applications. Some effectively allow you to "retrofit" security into an application as an element of overall system design.
The reasons for wanting to (or having to) retrofit security into an application are varied. Sometimes the reason can be as simple as necessity. Suppose that you're running an application found to have security flaws or perhaps lacking some important security features. You don't have access to its source code, and you have an overwhelming business need to continue to run it. If you find yourself in that position, the best solution is probably to engineer a security retrofit to the application. (A word of caution, though: you must be sure to treat the retrofit itself with the same level of scrutiny and care that you would for any business-critical software development effort.)
Although many of the approaches we present have been in use for decades, they have gained popularity and importance in the last few years. We think that is because of a widening awareness of just how hard it is to write vulnerability-free code.
The following sections describe several techniques of this kind, starting with the simplest and cleanest—wrappers.

Section 3.3.1.1: Wrappers

One way to make an existing application more secure is to use a wrapper. To do this, you first move the existing application to a special location (where it is, perhaps, invisible to ordinary users or unavailable for invocation in the usual way). You then replace the old application with a small program or script that:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Bad Practices
Sometimes it's easier for programmers to understand what they need to do if they can see clearly what not to do. The following sections list practices to avoid—security design mistakes we have either seen or, alas, made ourselves. We cover the overall design approach, as well as some specific design flaws.
The following practices describe common errors that pertain to the overall design approach:
Don't be too specific too soon
One trap that we've seen many application designers fall into is to start selecting specific controls or technologies without first thinking through and making a design—that is, to start coding before knowing what is to be done. Some people seem to want to jump straight from the policy level (e.g., "only authorized users can read our files") to decisions about details (e.g., "we'll use hardware password tokens," or "we'll use that XYZ software that checks passwords to make sure they're 8 characters long"). This is an all-too-easy mistake for engineers, who are problem solvers by nature, to make. Sometimes, it can be hard for us to leave an unsolved problem on the table or whiteboard, and stay at the conceptual level. Resist the temptation to solve that problem as long as you can. For one thing, you may be able to design it away!
Don't think about "what it does"
We alluded to this earlier in our discussion of mental models and metaphors. Many of the strangest vulnerabilities we've seen were built into applications at design time because the programmer indulged in the luxury of thinking "inside the box," created by the understanding of the application's purpose. Forget it.
At this point, we swallow our pride and list a number of specific design mistakes we ourselves have made. Looking back, we find that most of the design errors we've made have arisen when we allowed ourselves to be so concerned with the "security" aspects of business software that we forgot about the "business" part. So please avoid (as we failed to) the design flaws in the following list:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Case Studies
This section includes several case studies, including a relic from the mid-1980s implementing role-based access control, a couple of classic wrapper programs, a secure mail delivery system, and the 802.11 wireless LAN security design. We've carefully selected these examples—from real experiences—to give you insight into how others have approached difficult design problems.
The Access Control Executive (ACE) was a software system that Mark codesigned and coengineered in the mid-1980s. It provided key security services to many famous museums in Europe (and many other tightly secured locations). We include it as a case study as an example of a well-thought-out mental model.
We called the software the Access Control Executive because it ran as a background process and controlled access to all system resources. The ACE was consulted before any utility was successfully initiated; before any file was (through an application) opened, written, or closed; and before any vault (let's say) was opened. It gave a ruling on whether the action was to be permitted, denied, or modified, and this ruling was communicated back to the caller in real time.
By design, each application program had to ask the ACE for permission to do anything risky. Yet none of them was burdened with specific code to do this. Instead, at initialization each invoked a single routine that "signed on" to the ACE, and at the same time each one modified on the fly its copy of a small part of the system's library controlling input and output, program invocation, and a few other operations.
An alternate scheme we considered was to build the applications themselves with a modified version of the library. This would have obviated the need for any changes to the application source code at all! We rejected the idea because we worried that it would burden future maintainers of the code, forcing them to understand and follow highly specialized build techniques for all the applications.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Summary
As this chapter has shown, there is more to designing a secure application than merely "being careful" and "avoiding mistakes." In fact, we have known many experienced and capable programmers who first came to believe in the need for rigorous software engineering techniques when given the responsibility for maintaining security-sensitive code. It can be a humbling experience.
We hope that we have impressed on you the need for methodical security needs assessment as part of the design stage of any application software project. We also hope that you'll find useful our pointers to rigorous methods you can use to select appropriate security technologies and controls. Most importantly, we hope you will agree that designing errors out at the start is the best hope for security. Files that are never created can never be read or changed inappropriately. Treating all users the same—in fact, paying no attention to user identification—can (if appropriate) be much safer than relying on inadequate authentication. A password that is not required, and never coined, cannot be lent, stolen, or compromised. We've found that such simplifications can be made feasible more often than is generally understood. It is always worthwhile to look for these opportunities.
In the next chapter, we turn from architecture and design to the struggle for well-executed code. The best designs, of course, can be subverted or compromised by poor implementation. Perhaps the insights you've gained here (and the thorough appreciation for the complexity of secure design) will give you extra impetus to aspire to zero-defect implementation.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: Implementation
Your knowledge is of a meager and unsatisfactory kind; it may be the beginning of knowledge but you have scarcely in your thoughts advanced to the state of science.
—William Thomson, Lord Kelvin, On Measurement, 1894
An implementation flaw is a mistake made while writing the software; most, though not all, implementation flaws are coding flaws per se. In our view, implementation flaws typically arise because the programmer is either unfamiliar with secure coding techniques or unwilling to take the trouble to apply them. (No doubt because we like to believe the best in human nature, we think it's much rarer that someone tries hard and fails to successfully write secure code.)
Looking back to the example of the SYN flood attacks, there were certainly implementation flaws in addition to the principal design flaw that led to the attacks. For example, when the array of TCP sockets became exhausted, some operating systems at the time simply crashed. This was the result of a memory overflow that occurred when the software attempted to store an out-of-bounds array value. At the very least, a carefully implemented TCP stack could have prevented such catastrophic failure of the operating systems.
Source code is the final stage in the translation of a design into something users can use, prior to the software's being subjected to testing and (eventually) production. Flaws in source code, therefore, have a direct link to the user base; because the machine translation of the source code is exactly what gets executed by the computer at production time, there is no margin of error here. Even a superbly designed program or module can be rendered unsecure by a programmer who makes a mistake during this last crucial step.
Consider a simple example of a programming error in a web-based shopping cart. Imagine that an otherwise flawlessly designed and implemented program inverts a Euro-to-dollar currency conversion algorithm, so that a person paying with Euros ends up getting a 20% discount on goods purchased. Needless to say, when the first European makes a purchase and reviews the bill, a flood of gleeful purchases from Europe will ensue.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Good Practices
In this section, we provide lists of recommended practices in a number of categories.
George Santayana said, "Those who do not remember history are doomed to repeat it." This is certainly applicable to software implementation flaws. The lesson that we should take from this oft-repeated statement is that we can prevent at least the most common of implementation flaws by studying them and learning from them. We believe that everyone who writes software should take some time to study and understand the mistakes that others have made.
Some specific things that you can do include the following:
Follow vulnerability discussions
The Internet is home to a myriad of public forums where software vulnerability issues are frequently discussed. Quite often, particularly in so-called full disclosure groups, software source code examples of vulnerabilities and their solutions are provided. Seek out these groups and examples; study them and learn from them.
Read books and papers
In addition to this book, there have been dozens of excellent papers and books written on secure coding practices, as well as analyses of software flaws. Appendix A provides a good starting point for reading about mistakes and solutions.
Explore open source software
One of the side effects of the Open Source Software movement is the vast amount of software source code that is now available to programmers. As a result, there is no shortage of examples of how to perform various actions in pretty much any programming language. (Just beware, though, that you'll also find copious examples of how not to do things as well.)
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Bad Practices
Listing all of the things that you should do in implementing secure code is a good start. However, we're shooting at an ever-moving target, so it's only a start. It's equally important to list the things you shouldn't do. So, in this section, we examine a list of flawed practices, and offer our opinions and analyses of them. Note that, although we believe the list to be highly practical, we can't possibly presume it to be comprehensive.
We anticipate that some of our readers may find one or two of these tips "too obvious" for inclusion. Surely, some might say, no one would code up such mistakes! Rest easy! Your authors have found each and every one of these frightening creatures in living code. Further, we admit that—back in the bad old unenlightened days—we committed some of the worst errors ourselves.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Case Studies
In the following sections, we show the real-world consequences of some of implementation flaws we've seen over the years. We look at the flaws themselves, analyze their causes, and point out ways in which they might have been avoided.
Not all random numbers are created equal. In fact, as we mentioned earlier, choosing the right source for random numbers can be a vital step in implementing secure software. In one such publicized case, the MIT Kerberos 4 authentication protocol was implemented using a bad choice of random numbers. This resulted in an authentication protocol that could be quite easily compromised, simply by predicting subsequent random numbers from the source. In fact, this seemingly simple implementation problem—the result of a developer's making a poor judgment call—enabled an attacker to completely circumvent the otherwise well-designed cryptographic security of the Kerberos protocol.
This is a case where the design was sound, but the implementation was not. No doubt the design of the Kerberos session key generator specified the use of a random number in the algorithm that calculated each session key. However, what the design couldn't anticipate was that the team implementing the software used a random number generator that was never intended to be cryptographically sound. Sure enough, it generated statistically random numbers, but unfortunately those numbers were predictable.
Further, by the time that this vulnerability was discovered by a team at Purdue University the Kerberos system had been available in source code for several years. Even though dozens, if not hundreds, of software developers had reviewed the open system's design and source code, no one had noticed this vulnerability—even though Kerberos was designed to be a secure infrastructure component of MIT's Project Athena network system.
This case study teaches several lessons. The following are especially important:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Summary
Even though security flaws made at the design stage may be more costly and difficult to fix after the software is written, it is at the implementation stage that the "last chance for safety" occurs. Clearly, there are a great many things that you must keep in mind when implementing your design. Coding a software design is a process that requires a great deal of caution and care, and there is no substitute for experience. And even the experts often get it wrong!
We all can learn from how things are done in other industries. In the aviation industry, practitioners make extensive use of checklists, in addition to training pilots on an ongoing basis on how to properly operate their aircraft. They also intensely analyze the mistakes of others; whenever an accident takes place, the Federal Aviation Administration (here in the U.S.—no doubt other countries have similar practices) distributes a causal analysis memo to all pilots, for mandatory reading. We all are well advised to learn from that model. Study all the information that you can find; pedantically use checklists at each step of the development process; test and retest every aspect of your software.
Never assume that you have stopped learning how to implement secure code. Oh, and if you must make mistakes in your software, at least be original!
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 5: Operations
We didn't install the [Code Red] patch on those DMZ systems because they were only used for development and testing.
—Anonymous client, shortly after spending roughly 48 continuous hours removing 2001's Code Red worm from internal corporate servers
Throughout our careers, we've assessed the security of literally hundreds of major business applications. One of our most surprising (and disturbing) discoveries has been the apparent and thorough separation of application development staff from operating system and operations staff in major enterprises. In many of them, it seems as deeply rooted as the Constitutional separation of church and state in the U.S.
At one Fortune 500-level enterprise we examined, there was a nearly complete separation. The applications staff knew little of what the operations staff did and vice versa. There was even a separation of the security components of the applications and of the operating systems. In a number of cases, relatively secure applications were being placed upon unsecured operating systems and vice versa. It was evident that applications were not being deployed by a unified team. What particularly concerned us about this practice was the way that the employees we spoke with would thoroughly pass the buck of security to their counterparts, with no apparent desire to know the answers to the questions we were asking. We came away with the impression that this sterile separation would ultimately undermine the overall security of the enterprise.
Consider how an organization such as this might respond to the SYN flood attacks we've discussed throughout this book. Do you think that the application developers would think for a moment that a problem arising in the operating system's TCP subsystem should be their concern? And yet, do you think that their applications would be any less unavailable for legitimate use if they were hit with an attack?
Now that several years have passed, we feel all the more strongly that the security of an application and the security of an operational environment are inextricably tied to one another. To attend to one at the expense of the other is to neglect your duty to ensure that your overall business is secure.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Security Is Everybody's Problem
Before diving into the discussion of good and bad practices, let's explore this intertwining of application and operational environments. Why are these two aspects of security so closely tied to one another? After all, many modern client-server applications provide a single interface to the applications. What's wrong with authenticating users via that network path, and treating the security of the underlying operating system as completely separate?
Let's take a lesson from modern military doctrine. Direct, head-on attacks against an adversary have been proven time and again to be futile. They are really a last resort. Likewise, monolithic defense mechanisms inevitably yield to dedicated, well-equipped, and persistent adversaries. Thus, it stands to reason that someone attacking your applications would investigate multiple paths of attack and then carefully select the path of least resistance. The chances of that path's being the one you'd prefer—the direct network access to your application—are slim. To put it another way, it's at least likely that your applications will be attacked through paths that you may not initially anticipate. Your job is to ensure that all of the potential paths to your application are equally secured.
What other paths would there be, other than the direct network interface, you ask? Read on...
In the various security assessments we've performed over the years, we've found that there is almost always some means of remote connectivity allowing the administrative staff to perform day-to-day operational tasks on the operating systems supporting the various applications. (In Unix, this might mean that you have remote access to a command shell—perhaps via ssh or, heaven forbid, telnet; under the Windows 98/ME family, it could be an MS-DOS window, or a command prompt window on a Windows 2000/XP system.) While such operations are generally performed from a management console, production application server environments are rarely protected from network connections originating elsewhere within the enterprise. Sure, such administrative access is often necessary (or at least a matter of real practical convenience); but almost invariably it turns out that the application developers never consider the security implications of this access when they design their applications. Of course, they concentrate their security design efforts on the direct user interface to the applications, and more often than not, the security of the administrative access mechanisms are far less secure.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Good Practices
We'll start by describing many good things that you (or someone in your organization) ought to be doing.
You'll notice, we expect, that the following lists read largely like texts on how to secure an operating system or network. They are indeed a start in that direction. We don't want to leave the impression, however, that our lists are comprehensive. We invite you to read more detailed descriptions of how to secure your operating system separately. After all, many of the elements that we cite can—and have—been turned into entire volumes by themselves!
Still, these lists (which are directly derived from our experiences in assessing business applications) should stand you in good stead. We've layered the principles, starting with guidelines for networks and progressing up through operations procedures. (Figure 5-2 shows the layers more graphically.) One caution, however: make sure to consider the list as whole, and don't get caught in the trap of thinking that only one aspect of security is relevant to your job function.
Figure 5-2: Layers of security and operational practices
The security of most modern applications begins with the network on which they operate. One measure of a well-run data center is that the operations manager should know the business purpose for every packet of data that traverses the network. Don't laugh! We've seen examples of data centers that are that tightly configured. It's good for reliable operations as well as for the security of the environment.
Allow essential network services only
When you're deploying a business application in a production data center, you should only allow, onto and out of the network, those network protocols or services that are vital to that application. This may require some careful network design and segmentation, but the results are well worth the effort. Aside from being more secure than a network that supports a large array of general-purpose network protocols, a well-designed and well-partitioned production network usually provides operational performance advantages over a flatter network: each application's data tends to be isolated to fewer network segments.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Bad Practices
Content preview·