Sharks in the Moat
Page 35
As important as code reviews are, they will be useless if we do not properly protect the source code repository from undetected changes. Access control to source code must be heavily managed and watched, using least privilege to ensure developers can only access the minimum source code they need. Protecting versions of code must also be carried out, as no one should be able to directly modify versions that have already been approved or released. Proper identity management and audit trails are crucial so that we can track any change back to the original individual who performed the update. Change logs must be preserved for future review or forensic analysis. At a minimum, change logs should reflect the following:
Who – the identity of the person.
What – what was changed.
When – a timestamp.
Where – the name of the file created, updated or deleted.
Any coding activity must be tied back to specific requirements to prevent bells & whistles from being implemented, which can result in an increased attack surface. Use of a requirements traceability matrix is ideal for this case.
Beyond logical access to the repository, the servers that host the repository must be properly secured as well. As the move to virtual computing
in the cloud continues, the need for hardening operating systems becomes even more important. Often, copies of source code will be generated due to legitimate reasons, such as importing a copy for a static code analysis. These secondary storage locations must be secured to the same level as the original repository.
Chapter 38: The Product Role
People filling the Product role go by many different names – stakeholders, product managers, product owners, business owners, etc. The attribute that all share is that Product wants Development to build something for them, and Product represents the definitive source for all requirements. The Project role simply facilitates the process but does not generate requirements – that is up to Product to do.
In terms of secure software, we are going to discuss three key areas that Product must own and be actively engaged in – threat modeling, data classification, and policies that the software must align with.
Threat Modeling
In this section we are going to discuss how to identify and address vulnerabilities through a process called threat modeling. By following a well-defined series of steps, we can ensure end-to-end coverage of protection for any software or system. But first, we need to cover some basics. There are seven distinct categories of threat agents, or threat sources. We’ll cover them one at a time, from the most innocuous to the most dangerous.
Threat Sources and Agents
An ignorant user causes unintentional damage by causing user errors. This person does not mean to cause harm, but through a lack of either training or awareness takes some action that results in an incident. The only way to combat such a threat is to spend time and resources in training people. Organizations often think that creating good documentation or help guides will solve the problem, but most people are not likely to read such material unless required to do so.
An accidental user is an ordinary user who stumbles upon a mistake in software and is able to gain privileged access to information or functionality. This type of threat does not want to cause harm, but figures “Hey, this works. It won’t hurt if I take advantage of it, right?” Implementing the right security mechanisms is the only helpful response.
A curious attacker is a user who notices some anomaly in how software functions and decides to pursue it further. Often an accidental user turns into a curious attacker.
A script kiddie is a legitimate hacker who does not possess any special computer skills but can be dangerous because of the tools they use. Think of a 5-year old who picks up a machine gun and pulls the trigger. They really have no idea of the damage they could cause, and often don’t comprehend the power at their fingertips. Most elite hackers started out life as a script kiddie, and this category will be the most common external hacker you will encounter. Now, elite hackers use the same tools as script kiddies, but it is easy to tell the difference. A script kiddie will usually not know how to hide their foot prints on the software they are attacking, such as deleting log file entries or erasing all evidence of hidden files. If an attacker gets caught, they will usually be a script kiddie.
The most powerful and dangerous attacker doesn’t originate from outside of an organization, he or she will usually be an insider. Usually a disgruntled employee or staff member with access to inside knowledge, this attacker lives inside of the firewall. For example, a database administrator is a highly dangerous position as this employee will have direct access to sensitive and critical data. The only way to combat such a threat is to ensure a company has the proper identification, authentication, authorization and auditing controls in-place in a way that an insider cannot circumvent. Auditing is especially important as it acts as a detective control to uncover fraud or inside attacks, and the mere presence of effective auditing that is well-known to insiders can be a very good deterrent.
Organized cybercriminals are highly skilled individuals or organizations that are paid to breach system security, often with the goal of financial gain for their benefactors. This group has a deep understanding of software development, are capable of reverse engineering, and understand network and host security controls. Targets include both corporate assets as well as national security infrastructure. Malware developers and advanced persistent threats will almost always fall into this category.
And finally, we have third parties or suppliers that exist outside of the control of an organization yet have special access to the inner workings either because of a special relationship or due to the use of their software in an organization’s internal network. Malicious code can be embedded inside of software, such as logic bombs or Trojan horses. This can take place at any number of steps along the software supply chain. When outsourcing software development, it is crucial to understand how a third party is affected by foreign ownership or influence.
Now that we have a good understanding of threat agents, let’s get back to the subject of threat modeling.
Threat modeling is a crucial part of the design phase of any software project and helps to deliver hack-resilient software. It is closely aligned with minimizing the attack surface, as its primary goal is to identify all entry and exit points that can be exploited by an attacker. The premise is that unless we understand how software can be attacked, then we have little hope of applying the proper levels of protection. In the modern world of security, no software project should be considered ready for coding until a threat model has been completed.
The primary benefit to threat modeling during the design phase is that it can identify design flaws before a single line of code is written, greatly saving on re-implementation costs later. This model is iteratively matured as the architecture teams identify additional threats. During later phases, the implementation team will use the threat model to implement controls and write secure code. The testing team will use the model not only to generate test cases but also to validate which controls will need to be present outside of the software in the surrounding environment to ensure a secure infrastructure. The operations team will use the model to configure the software so that entry and exit points are secured.
Of course, creating a threat model is not all unicorns and rainbows. When done correctly, modeling can be a very time-consuming activity and requires a fairly mature SDLC to be successful. Employees will need to be trained to correctly model threats and address vulnerabilities. The average developer will not see the benefit of threat modeling and will prefer instead to jump right into coding – it takes a mature and self-disciplined development team to ensure all threats have been identified before laying down code. The same can be said of the testing team – they will tend to jump into defining test cases before the threat model has been completed if care is not taken. And perhaps the biggest challenge is that is it will be difficult to gain business support as it is har
d to show a demonstrable return on investment. In this last case, it might be of great value if the project leaders can point to previous projects showing the high cost of implementing security in latter stages of the SDLC.
In spite of the huge boon to security AND productivity, not everyone should jump on the threat modeling bandwagon. There must exist some very crucial prerequisites to avoid failure.
Prerequisites
First, security policies and standards must be clearly defined. Unless these documents exist and are expected to be enforced, the security team will encounter resistance from the business and development teams that cannot be overcome. In this case the iron triangle will quickly deprioritize any security efforts and there will be no compelling reason to move security measures higher in priority.
The company must be aware of compliance and regulatory requirements. These external requirements act in the same manner as internal security policies and standards to provide a basis for the security team to ensure a proper prioritization of security concepts.
The company must have a clearly defined and mature SDLC process. Whether a waterfall, iterative or agile methodology is used, the SDLC must be well-understood and followed. The alternative is an ad-hoc development process, which will always result in gaps in a threat model. We previously mentioned that generating a threat model is an iterative process, and the SDLC controls and enforces iterations or gates, depending on the SDLC. Both are required for their respective SDLC methodology but are often bypassed in an immature development organization.
The final prerequisite may seem to be obvious, but the attitude of planning to act on the threat model must exist. If we build a threat model and not use it, then we might as well all go out and buy exercise equipment with the full intention of putting it in storage and never using it. We will have just as much success in reaching our goals in both cases. If the threat model identifies some serious vulnerabilities, then we must be willing to mitigate those weaknesses regardless of how onerous the effort may appear to be.
If all four of the prerequisites we just listed cannot be put into place, then you should probably choose another approach to risk management. Of course, if your organization claims to take security seriously but is not willing to put these four non-negotiables into effect, then there are other problems in your culture that need to be solved first - whether you use threat modeling or not!
There is one last point to consider before running out and launching a threat modeling exercise – not all software is worth the effort. Modeling requires an extensive amount of resources and items to execute properly, and a company must be able to justify the expense. There really is not a software system or product that will not benefit from threat modeling – it is just a matter of priority to the company. Valid candidates include existing software, new projects, new versions of existing products and legacy software. If modeling legacy software, it is best to take on the effort only when the next version is being designed. When modeling third-party software or components, it is important to notify the owner or publisher and gain their permissions before proceeding as it might violate their EULA. For example, a EULA might prohibit exercises such as reverse engineering, which is often needed to properly model black box software in which the source code is not available.
The Process
Before diving into an analysis of threats to software, we must first establish the security goals that a given system is designed to provide. For example, is it supposed to protect data from being stolen? Is it designed to encrypt sensitive information? Should it provide high availability?
Some of the data points we can leverage to answer these questions are inputs such as internal company policies or standards, external regulations or privacy requirements, and internal requirements.
Threat modeling consists of four phases roughly summed up as: diagram, identify, implement and validate. Figure 96 provides a detailed view.
Figure 96: Threat Modeling Phases
Phase 1: Model the Application Architecture
If we don’t understand the application that is being built, we have little to no hope of accurately modeling threats. Therefore, the first phase is to understand and properly diagram how it works. To do this, we need to pay attention to five areas.
First, we need to identify the physical topology. This tells use where and how the completed application will be deployed. For example, will it be deployed into an internal environment only? Will part of it exist in a DMZ? Will it be hosted in a public cloud? We need to understand the environment in which it will live before continuing.
Second, the logical topology is defined. Logical tiers such as the presentation layer, business layer, data access layer and the data repository must be described. Sometimes the logical topology reflects the physical topology, but certainly not always. For example, the BL, or business layer, may reside as a stand-alone, middle-tier component in the form of web services, or in simpler applications it could live on the same server as the presentation tier, possibly even in the same process space. By the time we get through with this area, it should be abundantly clear how the tiers are laid out, both physically and logically.
During this time, we should also be noting what services, protocols and ports will either be implemented or are required for the application to function. Documenting the various identities that will be used and how authentication will be designed is also part of this second area. As examples, we will need to note if authentication is based on forms, certificates, tokens, biometrics, or SSO, and if it is to be multi-factor.
The third area to diagram includes human and non-human actors. For example, we will need to identify customers, sales agents, system administrators and database administrators.
Fourth, data elements need to be called out, such as product information, customer information, and other entities.
And finally, we need to take the human and non-human actors and the data elements previously defined and generate a data access control matrix. This is essentially a 2-dimensional table with data elements along one axis, and actors along the other axis. Where each meet, we simply define the access the actor will have to the data element. This can be any scheme we choose, but it is often helpful to use the CRUD approach. As an example, we might dictate that a sales agent only has ‘CRU’ access to a customer’s data to prevent them from deleting a customer, but still allow them to create and make updates to existing customers. An example is shown in Figure 97. As a side effect, this activity will help identify technologies used when building the application along with any external dependencies.
User Roles
Administrator
Customer
Sales Agent
Data
Customer Data
CRUD
CRUD
CRU
Product Data
CRUD
R
RU
Order Data
CRUD
CRUD
Credit Card Data
CRUD
RU
Figure 97: Data Access Control Matrix
Phase 2: Identify Threats
Now that we have proven we thoroughly understand the application, we are free to start identifying threats to that application. This is carried out using seven distinct steps.
The first step is to identify trust boundaries. A trust boundary is a point at which the level of required privilege changes. For example, if we are simply reviewing sales statistics, and then move into an area of the application where we can create new customers, we have moved from a low-privilege area into a higher-privileged one. In other words, we just crossed a trust boundary. By grouping functionality into trust areas, it is much easier to see where we will need to ensure the proper level of privilege is owned by the current user.
Next, we need to identify entry points, or points in the software that take in user input. If you recall, the attack surface is very dependent on the number of entry and exit points that exist. To properl
y model threats for a given system, we need to identify all entry points. Some examples of entry points might be the logon page, a search page or account maintenance options.
Closely related to entry points, is to identify exit points, which send information back to the application consumer – in essence, an entry point puts data into a system while an exit point takes data out of the system. Exit points can often leak dangerous information to an attacker and is best represented by sending back a page of HTML to a browser client. However, an exit point could just as easily be a web service API that returns data to a consuming application.
The fourth step when identifying threats is to identify data flows. Data flow diagrams, or DFDs, and sequence diagrams can greatly help us to understand how an application will accept, process and output data as it crosses various trust boundaries. DFDs show the flow of data, backend storage elements, and the relationships between data sources and destinations. Figure 98 provides a sample data flow.
Figure 98: A Data Flow Diagram
The fifth step is to identify privileged functionality. When previously creating the trust boundaries, we probably set the stage for this step, but now we need to explicitly identify specific functions that carry out operations requiring an elevated level of privilege. If you recall, the least common mechanism principle discourages the use of a single function from being invoked with two different privilege levels. This step is where we enforce that principle and separate out functions that would violate it.