Chapter 7. Stage 2: Define and Follow Design Best Practices

In this chapter:

The software industry abounds with security software coding best practices (few of which are followed), but there is a dearth of pragmatic secure-design guidance. Microsoft has spent considerable time working to make secure design accessible to the average non-security expert. Saltzer and Schroeder’s classic paper “The Protection of Information in Computer Systems” (Saltzer and Schroeder 1975, Computer Security Resource Center 2002) offers many time-tested secure-design principles that apply today as much as they did in 1975. Secure design is necessary for all computer software, from operating systems to online computer games (Yan and Randell 2005). This chapter offers brief ideas for applying secure-design principles to modern application software.

Extensive coverage of these principles is beyond the scope of this book; for more information, please refer to one or more of the many references (Anderson 2001, Bishop 2002, Howard and LeBlanc 2003) on the subject.

Internet Engineering Task Force (IETF) requests for comments (RFCs) must also include security information. Rescorla and Korver’s “Guidelines for Writing RFC Text on Security Considerations” (Rescorla and Korver 2003) offers some ideas on how to think about the security implications of software, firmware, and hardware features.

Best Practices

Best Practices

When you expect engineering staff to execute on security-related initiatives or to adhere to a security or privacy policy, it is imperative that you provide prescriptive guidance about how to achieve your goals. Don’t just say, “This is bad.” Instead, say, “This is the way you should do it.” In our experience, engineering staff are happy to adhere to security and privacy policies as long as you explain how to attain the desired objectives.

All products should follow appropriate secure-design best practices. These are not the same as threat modeling; threat modeling and secure design are different but complementary. Threat modeling determines appropriate mitigations based on threats to the system, and secure design best practices focus on “good security hygiene” within the application. For example, if you identify a threat to a system and then select mitigations, your mitigations could be compromised if the application’s design is insecure. Secure-design principles can help prevent such potential errors.

Another important best practice of the design phase is reducing a software product’s attack surface, which is the sum of all code and functionality accessible to users and potential attackers. For example, a Transmission Control Protocol (TCP) socket opened by an application is part of the application’s attack surface. Attack surface might appear to be an operating system characteristic only, but all applications have it, even if some applications measure it differently. A goal of any product should be to reduce the attack surface.

Note

Note

Remember the two major goals for the Security Development Lifecycle (SDL): reduce the number of vulnerabilities in the software as you develop it, and reduce the severity of any undiscovered security bugs. The first principle is the high-level goal of Secure by Design, and the second is the high-level goal of Secure by Default. Securing the design and the code is paramount, but mistakes will be made, and research into new vulnerabilities that may affect the software continues long after a product has been shipped to customers. It is therefore imperative that the product have a minimal attack surface to reduce the severity of any security bugs in the code. This is what secure by default is all about; secure by design is about getting things right, and secure by default is recognizing you never will!

Common Secure-Design Principles

Of the numerous secure-design principles, the classic and most quoted are those in the list created by Saltzer and Schroeder in their seminal paper, “The Protection of Information in Computer Systems.” These principles, although written in 1975, are still valid today and apply especially to security software:

  • Economy of mechanism. Keep the code and design simple and small. The more complex the software, the greater the likelihood of bugs in the code. When the code is small, less can go wrong.

  • Fail-safe defaults. The default action for any request should be to deny the action. Thus, if the user request fails, the system remains secure.

  • Complete mediation. Every access to every protected object should be validated. Follow the best practice of performing the check as close to the protected object as possible. For example, if your Web-based application protects a file, operating system file system access control lists (ACLs) are a more robust protection mechanism than an access check within your Web-based code.

  • Open design. Open design, as opposed to “security through obscurity,” suggests that designs should not be secret. The most well-known embodiment of this principle is Kerchoff’s Law, which applied to cryptographic designs states, “The system should not depend on secrecy, and it should be able to fall into enemy hands without disadvantage” (Wikipedia 2006).

  • Separation of privilege. Do not permit an operation based on one condition. Examples include two-factor authentication, and, at a higher level, separation of duties.

  • Least privilege. Operate with the lowest level of privilege necessary to perform the required tasks. This subject is covered in more detail later in this chapter.

  • Least common mechanism. Minimize shared resources such as files and variables. You can more easily control individual processes manipulating private files than two processes manipulating the same file. Furthermore, code that uses only local variables is more robust and maintainable than code that uses global variables.

  • Psychological acceptability. Is your secured product easy to use? If not, it won’t be used. You should always ask yourself, “Can I implement this system in a way that makes the product easier to use?” Never forget about your users. Psychological acceptability requires a great deal of skill and user interface design expertise.

Caution

Caution

Psychological acceptability is hard to get right; if a very secure system is difficult to use, users might abandon the security features of the product. As we developed Microsoft Windows XP SP2, we carefully balanced security, the main focus of the service pack; usability; and backward compatibility. We recognized, for example, that if the firewall prevented too many applications from working or if some defenses made the system hard to use, users would simply disable the defenses, making their systems more susceptible to successful attack and rendering all the protective work useless. A key lesson is to be wary of security for the sake of security.

Various resources address secure design; we urge you to consider the references listed at the end of this chapter for further study.

A product’s security features do not necessarily secure the product from attack. Any feature, whether or not it’s a security feature, must be implemented as a “secure feature” and be engineered correctly, with appropriate attention to security and quality. All input must be rigorously validated for correctness.

Best Practices

Best Practices

Remember, even the most secure design is rendered pointless by a low-quality and insecure implementation, regardless of the number of security features the product employs.

“Bolting on” security or privacy later in the schedule, or after the features are complete, is not an option. The only way to deliver robust security and privacy consistently to customers is by including those qualities in the application during the design phase.

Attack Surface Analysis and Attack Surface Reduction

Any useful application employs code accessible to end users and attackers alike. Code almost always has bugs, some of which are security related. Accessible code might be vulnerable to malicious users.

Note

Note

The inspiration for Attack Surface Analysis (ASA) and Attack Surface Reduction (ASR) comes from Saltzer and Schroeder’s principles, most notably, least privilege and economy of mechanism.

Attack Surface Analysis and Attack Surface Reduction are all about understanding what constitutes the attack surface of your application and how you can effectively reduce it to prevent an attacker from taking advantage of potentially defective code. The software industry worries a lot about improving code quality. But although code quality is exceptionally important, new classes of vulnerabilities may affect even the best code, so we cannot focus exclusively on getting the code right. Even if your code happens to be perfect, it’s only perfect by today’s standards—a snapshot of best practices at development time. Yet the vulnerability research landscape is constantly evolving. Five or so years ago, integer overflow vulnerabilities were almost unknown; today they are an extremely common attack.

Best Practices

Best Practices

The software industry needs to change its outlook from trying to achieve code perfection to recognizing that code will always have security bugs. We must therefore focus on extra defense mechanisms. But of course, we should never stop trying to achieve software perfection.

The attack surface of a software product is the union of code, interfaces, services, and protocols available to all users, especially what is accessible by unauthenticated or remote users. ASA is the process of enumerating all the interfaces and protocols and executing code. The rest of this chapter will give you an idea of elements you need to consider during the ASR phase. Code that is part of the attack surface is more vulnerable to attack. For example, the code behind a remotely accessible socket is more at risk of attack than, say, the code behind a closed socket.

The core tenet of ASR is that all code has a nonzero likelihood of containing one or more vulnerabilities. Some vulnerabilities result in customer compromises. Therefore, the only way to avoid customer compromises is to reduce code usage to zero. ASR compromises between perfect safety and unmitigated risk by minimizing code exposed to untrusted users. Code quality and ASR can help produce software that is more secure; striving to write perfect code alone will not.

Best Practices

Best Practices

Code with a large attack surface—that is, a large amount of code accessible to untrusted users—must be extremely high-quality code. It must be extensively hand-reviewed and tested.

At a high level, ASR focuses on:

  • Reducing the amount of code that executes by default.

  • Restricting the scope of who can access the code.

  • Restricting the scope of which identities can access code.

  • Reducing the privilege of the code.

Figure 7-1 shows the steps you should follow when considering the attack surface of your application.

Follow these steps to reduce attack surface.

Figure 7-1. Follow these steps to reduce attack surface.

Step 1: Is This Feature Really That Important?

The first task is incredibly important. For each of the product’s features (especially services, daemons, mobile code such as ActiveX controls and Java applets, running applications, and so on), you should ask, “Is this feature needed by at least 80 percent of our users?” If the answer is no, the feature should be turned off, not installed, or disabled by default.

A good example of this kind of ASR is the Internet Information Services (IIS) 6.0 Web server in Microsoft Windows Server 2003. It is not installed by default, unlike IIS 5.0 in Microsoft Windows 2000, which is installed by default.

Important

Important

Disabling a feature by default does not mean that you can ship a poor-quality feature. Disabling a feature will reduce, not prevent, the likelihood of many users being impacted by a potential bug.

Next, you should consider all the sub-features that make up the overall feature. This is probably best explained through example. A Web server, such as Apache or IIS, ships with a lot more functionality than just HTTP 1.0 or HTTP 1.1 processing. These servers can parse and respond to

  • Various HTTP verbs (GET, POST, HEAD, and so on).

  • WebDAV requests (PROPFIND, PROPPATCH, SEARCH, and so on).

  • SOAP Web service requests (all exposed SOAP methods).

  • Requests to Java Server (.jsp files), CGI (.pl or .cgi), PHP (.php), ASP (.asp), or ASP.NET (.aspx) applications.

  • Requests to ISAPI filters and applications or Apache modules (such as mod_rewrite).

  • SSL and non-SSL requests (including SSL2, SSL3, PCT, and TLS variants).

Remember, each of the preceding sub-features is a separate code path, and that code probably has security bugs. Hence, you have to determine whether it makes sense to enable all this micro-functionality by default. Again, IIS 6.0 is a great example of micro-ASR; when the Web server is enabled, it responds only to requests for static files, and that code path is relatively small. If you want to enable, say, WebDAV, you must opt in for that functionality. Two years after the release of IIS 6.0, Microsoft had issued only one security bulletin for the Web server; the bug was a denial-of-service vulnerability in WebDAV, which was shared with IIS 5.0. The bulletin MS04-030, “Vulnerability in WebDAV XML Message Handler Could Lead to a Denial of Service” (Microsoft 2004), is an update rated as important for Windows 2000 users and moderate for Microsoft Windows Server 2003 users because in Windows 2000, WebDAV is enabled by default, and in Windows Server 2003, it is an “opt-in” feature and hence is less severe.

Step 2: Who Needs Access to the Functionality and from Where?

A viable application must have some useful functionality enabled by default, so the next step is to determine who can access the code and from where. As you see in Figure 7-2, code that is accessible remotely by anonymous users has a larger attack surface than code that is accessible only to local administrators.

Accessibility increases attack surface.

Figure 7-2. Accessibility increases attack surface.

What follows is a good example of reducing the attack surface of a network-facing component. Windows Server 2003 users were unaffected by the Sasser worm (Microsoft 2005a) even though the code included the vulnerable security bug because the network endpoint that the worm attacked was accessible only to administrators seated at the keyboard. Microsoft developers had introduced an explicit “local administrator only” check in the remote procedure call (RPC) code during design reviews of the product. In Windows 2000 and Windows XP, this network interface was remotely accessible to anonymous users. Likewise, the Zotob worm did not affect Windows XP SP2 users (Microsoft 2005b) because in Windows XP SP2 and later versions of Windows, all RPC traffic must be authenticated before full communication can occur. Moreover, because malicious code such as Zotob is not authenticated (there is no valid user name and password associated with the payload), the attack could not penetrate to the vulnerable code. Lessons learned from the Blaster worm prompted the change in RPC attack surface in Windows XP SP2. Also, Windows XP SP2 explicitly enabled the firewall by default, blocking the RPC ports at the computer’s IP network layer. This is a great example of multilayer defenses.

You should consider each piece of functionality individually in your application to determine who needs to access the code by default (anonymous, user, or a specific group of users or administrators) and from where they should access it (remote, remote but only from a specific set of addresses or a subnet, site-local or link-local [IPv6], or local-only).

You can require valid user account access by using authentication and authorization techniques. Use techniques provided at the lowest possible level of your system, such as those in the operating system or those in a class library your application relies on, such as the Microsoft .NET Framework or the Java Runtime libraries.

Caution

Caution

Do not create your own authentication or authorization mechanisms unless the underlying mechanisms absolutely do not provide what you need. And if you still think you need to create your own mechanisms, think again!

You can often restrict network accessibility by using a firewall, but you should consider adding another layer of defense in case the firewall is disabled.

Important

Important

Never depend on a firewall as your sole defense. Firewalls are exceptionally good perimeter defenses, but too often they are turned off or left open. How many stories have you heard of users being told to turn off their firewalls because an application didn’t work correctly? The firewall is always the first suspect.

Perhaps the better way to restrict network accessibility is by a configuration switch that defaults to the local machine, the local subnet (such as 192.168.x.x, 10.x.x.x, or an internal corporate address), or site-local or link-local for IPv6 networks. You can then set network accessibility to “no restrictions” for users or environments that require this added level of connectivity.

Tip

Tip

In .NET code, you can use the IPAddress.IsLoopback function to determine whether a connection is from the local machine and whether it works with IPv4 and IPv6.

Best Practices

Best Practices

If your application is to analyze IP addresses, make sure the code can parse IPv6 as well as IPv4 addresses; Microsoft has a tool named checkv4 that can check WinSock C/C++ code for IPv4-specific dependencies (Microsoft 2006).

Step 3: Reduce Privilege

The last step in reducing attack surface is to ascertain the privilege level under which the code operates. This applies mainly to long-running processes such as Windows services or *nix daemon processes. Processes that are exploited when running in a Local System or root context can create catastrophic failure because the exploit code will also run in the same context, and these accounts have access to all resources on the compromised computer. It is therefore imperative that you run code with just enough privilege to get the job done, and no more.

In Windows, “privilege” has two aspects that must be evaluated: the privileges associated with the account (Microsoft 2005c) and the group membership associated with the account. Privileges allow an account to do computer-wide tasks such as debug an application or backup files. Sun Corporation’s Solaris 10 operating system has a similar model (Rich 2005), as do POSIX capabilities in some versions of Linux (Solar and Mondi 2005).

In Windows, you can create an account that has just the privileges you want and have your service run under that account. Another way to solve the least-privilege problem is to run the service under a well-known account, such as Network Service, and then drop the privileges you don’t need by calling AdjustTokenPrivileges(...,SE_PRIVILEGE_REMOVED,...) on application startup. Windows Vista goes one step further by allowing you to define only the privileges you need by calling ChangeServiceConfig2(...,SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO,...).

As for group membership, the most dangerous group is the Administrators group, and the only way to exclude this security identifier from the application token is to run the application as a non-administrator in the first place. In *nix, you can create a special group for the application and use setgid <groupname>.

Services and Low Privilege

Rather than running your Windows services as Local System (also referred to as SYSTEM), you should use less-risky service accounts such as Network Service or Local Service unless there is a very good reason to run under the Local System account.

Sometimes your service simply must run as the Local System account because the code performs some form of system-wide management or security-related tasks. But you can still run with lower privilege by splitting the application into more than one executable process and running only the management process with elevated privileges while the user-facing code runs with a lower privilege. Apache and IIS 6.0 use this model. In the case of Apache on *nix, the first httpd process starts up as root, and its role is to start, stop, and control other httpd process and open the HTTP ports. The spawned processes run with lower-privilege accounts such as the “nobody” or “apache” account. In the case of IIS6, the main administrative service runs as SYSTEM, but the main processes that handle user requests run as the much-lower-privilege Network Service account. The high-privilege administrator processes don’t handle any user requests, and this decreases the potential threat to the high-privilege code. Figure 7-3 gives you an idea of how this pattern manifests itself.

Split an application into multiple processes based on privilege. The low-privilege processes handle untrusted user requests, and the high-privilege process handles administrative tasks.

Figure 7-3. Split an application into multiple processes based on privilege. The low-privilege processes handle untrusted user requests, and the high-privilege process handles administrative tasks.

More Attack Surface Elements

Depending on the operating system or application you use, other elements of attack surface should be investigated. The following elements are some of the most important.

UDP vs. TCP

User Datagram Protocol (UDP) has a higher attack surface than TCP because the source IP address is easily spoofed. TCP performs a full three-way handshake to verify the address and port of the caller and callee, whereas UDP is a datagram “fire and forget” protocol. We’re not saying you should remove UDP support from your application; the UDP protocol simply increases the attack surface of your product.

Note

Note

In Windows XP SP2 and later versions, all RPC datagram protocols are disabled by default to reduce attack surface.

Weak Permissions vs. Strong Permissions

A weak permission or ACL on an operating system object can render the computer vulnerable. In general, the default permissions on Windows objects are good enough, but you should always review the ACL your setup code explicitly sets on an object to make sure it offers appropriate defense. The same rule applies to *nix; you should review your code that sets permissions to make sure untrusted users do not have unnecessary access to the object.

An example of a weak ACL includes an ACL in a device driver that allows a normal user to overwrite the valid driver with rogue software. When the operating system loads the driver, the user’s code, not the valid device driver, is loaded into kernel mode. This is an example of a local privilege-elevation bug.

.NET Code vs. ActiveX Code

The Microsoft .NET technology was designed from the ground up to support fine-grained permissions enforced by a central run-time policy engine. ActiveX controls have no such restrictions; hence, ActiveX controls have a larger attack surface. Sometimes an ActiveX control is the most appropriate solution to a problem, but not all the time. Always consider managed run-time technologies first. If they’re not appropriate, consider ActiveX.

ActiveX “Safe for Scripting”

If you absolutely must create an ActiveX control, make sure it’s not marked safe for scripting unless it’s absolutely safe to call the control from untrusted mobile code such as JavaScript running in a Web browser. ActiveX controls that are marked safe for scripting have a larger attack surface than ActiveX controls that are not marked this way because these controls are accessible to low-trust code. One infamous example is an ActiveX control used to uninstall the XCP digital rights management (DRM) software written by First 4 Internet and distributed on some Sony BMG audio CDs. The uninstall control is marked safe for scripting and supports several potentially dangerous methods, including RebootMachine, InstallUpdate, and IsAdministrator.

ActiveX SiteLocked Controls

Web sites can render many forms of mobile code from HTML pages, and in many cases, mobile code that resides on a computer can be called by any Web page, including Web pages from malicious Web sites. ActiveX can limit which Web sites can call a control named SiteLocking (Microsoft 2002), which enables an ActiveX developer to restrict access so that the control is accessible only from a predetermined list of domains. This limits the ability of Web page authors to reuse the control for malicious purposes. You can also use the SiteLock template to make a control that behaves differently in different domains. The template consolidates domain checking into a single shared library that makes the ActiveX much more secure and much easier to fix when a problem arises.

A SiteLocked ActiveX control has a smaller attack surface than a non-SiteLocked control because the number of domains that can access the control is smaller.

Managed Code AllowPartiallyTrustedCallers Attribute

Strong-named assemblies marked with the AllowPartiallyTrustedCallers attribute (APTCA) can be called by code that is not fully trusted, such as code running from the Internet.

Note

Note

A strong name consists of the assembly’s identity—its text name, version, and culture information—plus a public key and a digital signature.

You should mark your strong-named assembly with the APTCA only when your code must categorically be called from non-Full Trust code. Because code marked with APTCA can be called by less-trusted code, APTCA increases the attack surface of the code.

Table 7-1 lists attributes of an application that contribute to larger or smaller attack surfaces.

Table 7-1. Relative Attack Surface Rankings

Higher Attack Surface

Lower Attack Surface

Feature running by default

Feature not running by default

Open network connection

Closed network connection

Listening for UDP and TCP traffic

Listening only for TCP traffic

Anonymous access

Authenticated user access

Authenticated user access

Administrator access (be careful not to make too much code admin-only because this can start violating the principle of least privilege)

Internet access

Subnet, link-local, or site-local access

Subnet, link-local, or site-local access

Local machine access

Code running with Administrator, Local System, or root privileges

Code running with Network Service, Local Service, or custom low-privilege account

Weak object permissions

Strong object permissions

ActiveX control

.NET code

ActiveX control marked safe for scripting

ActiveX control not marked safe for scripting

Non-SiteLocked ActiveX control

SiteLocked ActiveX control

Table 7-2 shows examples of how Microsoft has reduced the attack surface of some commonly used products.

Table 7-2. Attack Surface Reduction in Some Microsoft Products

Product

Attack Surface Reduction Step

Example of. . .

Microsoft Office 2003

Do not install various file format filters

Reducing running code

 

Run by default only signed and trusted macros

Reducing Office code paths to trusted code

Microsoft Exchange Server 2003

Turn off POP, IMAP, and NNTP by default

Reducing running code

 

Allow only trusted users to create root public folders

Strong permissions

 

Disable many less-used RPC interfaces

Reducing running code

Microsoft Visual Studio 2005

Microsoft SQL Server Express allows only local connections by default

Reducing network accessibility

 

Web server allows local connections by default

Reducing network accessibility

 

ASP.NET runs as a non-admin account

Least privilege

 

Web services reject HTTP GET requests

Reducing running code

 

Debugging requires group membership

Strong permissions

Windows XP SP2

All RPC communication must be authenticated

Strong permissions

 

Turn on firewall by default

Reducing network accessibility

 

Disable some services (for example, NetDDE)

Reducing running code

 

No longer run some services as Local System (for example, RPC)

Least privilege

SQL Server 2005

Main SQL Server process runs as Network Service

Least privilege

 

Disable xp_cmdshell

Reducing running code

 

Disable .NET common language runtime

Reducing running code

 

Disable COM integration

Reducing running code

 

Disable ad hoc remote queries

Reducing running code

Developers have taken SQL Server 2005 one step further than most products, providing a small tool to determine which functionality is enabled or disabled by default and which networking protocols can be used. Figure 7-4 and Figure 7-5 show the SQL Server 2005 Surface Area Configuration tool.

SQL Server 2005 can reduce features.

Figure 7-4. SQL Server 2005 can reduce features.

SQL Server 2005 can reduce network access.

Figure 7-5. SQL Server 2005 can reduce network access.

Important

Important

Attack Surface Reduction is as important as getting the code right because you will never get the code perfect!

Best Practices

Best Practices

Reduce attack surface early; do not wait until the product is nearly complete before you think about how you’ll reduce the amount of code exposed by default to untrusted users.

We finish this section with a very important point. Personal firewalls, or firewalls installed on individual computers, are here to stay regardless of the operating system installed on the computer. Do not simply punch arbitrary holes in the firewall, and certainly do not tell users to turn the firewall off to run your application, even if the user’s enterprise has a perimeter firewall. This is especially true for portable computers, which are often used outside the defenses offered by the corporate firewall. Build your application with an understanding that the machine on which it will run probably has a firewall installed, and that firewall should not be disabled.

Summary

In recent years, a lot of attention has been paid to secure-coding best practices and much less to secure-design principles. The SDL mandates that engineers spend time in the design phase thinking about the security of features and implementing secure designs. It’s important that you learn the well-respected secure-design principles by reviewing and learning from some of the references in the following section.

Attack Surface Analysis is just as important as trying to secure the code because you will never secure the code 100 percent—you cannot predict the future, and humans make mistakes. The product you ship embodies a subset of the security best practices of the day, yet software security research continues. Document your attack surface, and aim to reduce it as much as is consistent with a usable product.

References

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset