The software security discipline is full of terminology and it’s important to state our particular definitions for these terms in the context of GrammaTech products and our approach to improving software security. This is not an exhaustive list but it does include some of the most popular phrases used with respect to software development processes and tools that are used in security-related work.
Software security is largely risk management; identifying, analyzing, prioritizing then mitigating risks. The risk of poor software security includes, among many other things, data breaches, malware infiltration, unwanted access and denial of service. Software security also means engineering a product (an application, a service, or a device) to continue to operate normally while under attack. To achieve this, software security includes the pursuit of identifying and removing potential security vulnerabilities throughout the software development lifecycle (SDLC).
DevSecOps (Development-Security-Operations) improves the DevOps (Development-Operations) pipeline to where security is a critical part of the development process. The realization here is that a security failure is the same, or worse, as a quality failure. Security is a differentiator but not at the expense of innovation and time to market. Software organizations don’t intentionally leave out security but unless it’s part of the development culture, it doesn’t get done. At huge risk, software teams are delegating security until the end of the development. Unfortunately, you can’t ‘tack on’ security at the end.
Making security part of an organization culture and DevOps pipeline requires careful planning, training, expertise and the right automation support. To reduce the impact of DevSecOps the right tools integrated into the security and quality process is the key.
In addition, a key reason to build security into agile and continuous processes is to build upon the knowledge that accumulates over the project. It’s not reasonable to expect software teams to understand their complete attack surface, for example, at the beginning of the project. Building security into day-to-day operations accumulates expertise and knowledge. Starting early is the key. This often referred to as “shifting left” or introducing security into the development phases of the SDLC. With that in mind, DevSecOps is often illustrated as follows on the DevOps flowchart – security in every part of cycle:
Source: “Tripwire - Security at the Speed of DevOps”
Code security refers to software security specifically as it pertains to source code, coding and software implementation. Code security is a big part of software security but since software is more than just new or existing code, it’s important to make the distinction. The use of third-party and open source code are technically still code but are usually treated differently by development organizations. When establishing security controls, it’s critical that any distinction be well defined. It’s also important to point out that software security applies to all stages of software development and code security is mostly focused on the implementation phase.
Related to code security is the analysis of code artifacts to help detect code defects and prevent security vulnerabilities.
Source Code Analysis
Source code analysis usually refers to static source code analysis, shortened to static analysis. In the software security realm static analysis tools are also used as static application security testing (SAST) tools as well. More on that distinction later. Static source code analysis is much too tedious to be performed manually, so static analysis tools are used to automate the testing process.
Static (source code) analysis tools are designed to look for bugs, poor coding practices, potential security vulnerabilities and coding standard compliance. Like a compiler, a static analysis tool does a build of your code using your existing build environment, but instead of creating object code, it creates an abstract model of your entire program. From the derived model, the tool’s symbolic execution engine explores program paths, reasoning about program variables and how they relate. Advanced theorem-proving technology prunes infeasible program paths from the exploration.
Checkers perform static code analysis to find common defects, violations of policies, etc. Checkers operate by traversing or querying the model, looking for particular properties or patterns that indicate defects. Sophisticated symbolic execution techniques explore paths through a control-flow graph, the data structure representing paths that might be traversed by a program during its execution. When the path exploration notices an anomaly, a warning is generated.
An astronomical number of combinations of circumstances must be modeled and explored, so advanced tools must employ a variety of strategies to ensure scalability. For example, procedure summaries are refined and compacted during the analysis, and paths are explored in an order that minimizes paging.
Static Analysis (and SAST) with CodeSonar
GrammaTech CodeSonar employs a unified dataflow and symbolic execution analysis that examines the computation of the complete application. By not relying on pattern matching or similar approximations, the CodeSonar static analysis engine is extraordinarily deep, finding 3-5 times more defects on average than other static analysis tools.
Unlike many software development tools, such as testing tools, compilers, configuration management, etc., SAST tools can be integrated into a team's development process at any time with ease. SAST technologies like CodeSonar simply attach to your existing build environments to add analysis information to your verification process.
Binary Code Analysis
When source code isn’t available, it is still possible to perform code analysis on binary artifacts such as binary libraries and executables. Even without debugging information (“stripped”) binaries can still provide useful information. Tools such as GrammaTech CodeSonar binary code analysis is able to extract useful information from stripped executables. CodeSonar, however, can analyze both stripped and unstripped executables.
Through this evolution in static code analysis, developers can inspect and evaluate all externally-produced code used in their applications. Binary analysis results can also be used to compare and contrast the relative safety and security of different third-party components, so teams can make the best possible decision when choosing components to include in their applications.
For software developed entirely in-house, full source code is usually available for analysis. If third-party binary libraries are being used however, then the analysis must be able to analyze both source and binary simultaneously in an integrated fashion. For example, CodeSonar can analyze such code, so results take into account the flow of control and information between the source parts and the binary parts.
Source Code Visualization
Code is complex and often hard to understand, especially when inspecting someone else’s work. Code visualization is making visual models that help in understanding the structure and flow of data and control in an application. In the context of software security and code analysis, visualization plays a role in understanding and tracing the root cause of vulnerabilities. A clear example of when visualization is handy in security engineering, is with tainted data analysis.
In the parlance of secure programming, unchecked input values are said to be tainted. Tainted data vulnerabilities should always be a concern for developers. Any software that reads input from any type of input, whether from a user interface or over a network connection, should treat all values as potentially dangerous. The values might be out-of-range intentionally or not, and if the program is not prepared to check the values, then they might cause the software to crash later. The infamous SQL injection vulnerability is the classic example of a tainted data attack. The same techniques that defend against security vulnerabilities can also be used to defend against rogue data values, so taint analysis techniques are also effective at finding and improving the security in the riskiest parts of the code.
Tainted data can flow through a program in unexpected ways, so an automated tool can also play an important role by helping programmers understand these channels. In CodeSonar, the location of tainted data sources (i.e. inputs) and sinks (where data is used) can be visualized and program elements involved in flows can be overlaid on top of a regular code view. This can help developers understand the risk of their code and aid them in deciding how best to change the code to shut down the vulnerability.
A top-down view of the call graph of the program showing modules according to the physical layout of code in files and directories. The red coloration shows the modules with the most taint sources, and the blue “glow” shows modules with taint sinks.
Software Security Testing
The focus of software security testing is to improve the resilience of a software product to cyberattacks by discovering vulnerabilities and other security risks. Security testing is sometimes assumed to be a late-stage development task when all the software is built. Running simulated attacks, penetrations tests and dynamic analysis tools to discover any critical vulnerabilities that made it this far during development, catch them and then fix them. However, the best approach is to consider software security testing to be part of every phase of development from inception, requirements, coding, testing and deployment – DevSecOps.
The use of tools and techniques like source code analysis (or SAST) during coding is also considered a form of software security testing. Any time you are evaluating the software against your security policies and controls you are security testing. When you are analyzing source code, for example, using tools and techniques that don’t require running code, it is considered static security testing. When actively performing manual and automated security tests on the running application, you are dynamic security testing.
Application Security Testing
Application security testing (AST) is strengthening and evaluating the security of a software product at the application level. This distinction is important because applications, especially web applications, run on top of multiple layers that each must have their own security testing and focus. For example, web application testing wouldn’t focus on securing the web server and OS levels that it will eventually be deployed to (not that these aren’t critical too!).
The focus of AST is securing the application, by testing its interfaces, code, and interactions with dependencies, services other applications. In terms of tools, static tools would concentrate on the source or binary code that make up the application and dynamic tools would be used on external and internal interfaces and on the running application itself (i.e. with instrumentation.)
Static Application Security Testing (SAST)
“Static application security testing (SAST) is a type of security testing that relies on inspecting the source code of an application. In general, SAST involves looking at the ways the code is designed to pinpoint possible security flaws.” (Source: Technopedia)
Strictly speaking, any kind of inspection of source (and binaries) is considered static testing. However, most practical applications include the use of automated static analysis tools, such as GrammaTech CodeSonar. SAST tools are key to helping prevent poor coding practices and software weaknesses from “blooming” into full-grown vulnerabilities. Here are some of the typical software problems that SAST tools detect:
Memory issues: Memory issues are generally dangerous and can either leak potentially sensitive information (confidentiality) if the problem is related to reading memory and/or can be used to subvert the flow of execution if the problem is related to writing memory (Integrity). Examples of these problems are buffer overrun/underrun, use-after-free, type overrun/underrun, null string termination, not allocating space for string termination, and negative character value. CodeSonar is particularly good at finding complex static and dynamic memory issues.
Programming Errors: This class of errors are mainly due to incorrect use of the programming language such as uninitialized variables, double freeing of pointers, implicit conversion between signed and unsigned, etc. These errors may not manifest themselves during testing since error conditions may not be triggered. However, they might be exploitable and have an impact on data confidentiality, Integrity as well as availability.
Dangerous Function Calls: Certain API or library functions are considered potentially harmful and unsecure. The C library function gets() is a great example, as it can easily overflow the destination buffer, leading to buffer overrun and hence impact Integrity. Other functions may have implementation specific behavior. These types of dangerous function calls are easy to find by static analysis tools as they can simply analyze the code and search for a list of dangerous functions.
Cryptography Misuse: Cryptography functions are important to keep data, in motion as well as at rest, confidential. However, few people are experts in its use and misuse of C library cryptographic functions can lead to problems. For example, the use of weak cryptography such as DES, MD5, or use of functions such as the C library function crypt(). Other examples are hardcoded keys or salt data for hashes. Problems in this category impact data confidentiality and integrity and are easy to find with static analysis tools.
Tainted Data: As discussed above, static analysis can alert the developer of these weaknesses early in the development cycle. Data that flows into the system through some form of input from a user, a device, a socket, anything is traced from source (where it enters the software) to its sink (or eventual use). Before that data is used in API calls, or used in any part of logic, it needs to be validated. If not, it could lead to serious vulnerabilities such as format string injection, LDAP injection, SQL injection, or other type of data injection exploit. You need to have a strong static analysis tool to find these problems using dataflow analysis and symbolic execution.
Secure Coding Standards and Enforcement: Due to the need for security in many mission-critical applications, industry standards groups have created software development best practices, guidelines, and certification processes for safety and security. Today, several secure coding standards have been adopted by various industries, including the following: Software Engineering Institutes CERT C and C++, MITRE’s CWE, MISRA C/C++ and others.
Central to each of these secure coding standards is guidance on reducing the probability of poor coding practices and software weaknesses by limiting the scope of the programming language to a safer and more secure subset.
SAST tools like CodeSonar simplify the enforcement of coding standards across teams, improving the overall compliance for a required coding standard and security of the code. Advantages to using automated SAST tools are building the necessary skills and understanding of the coding standard and the motivation for preventing certain constructs, automated enforcement and generation of the documentation requirements of the standards.
Dynamic Application Security Testing (DAST)
Dynamic application security testing (DAST) is considered black-box testing, where the tester has no knowledge of what’s inside the application (the “box” in this case.) DAST usually implies the use of tools that detect issues with an application while it’s running. This might be done through instrumenting the source code or binaries of the application or through observing it while executing operating system capabilities. The key differentiation with SAST is that the application must be executing while DAST is running, hence “dynamic.”
DAST also includes fuzzing which is a form of testing that throws random, extraneous out-of-bounds data at the application, often rapidly and in large volumes. Typically used by penetration testing (pen test) tools to “break” an application either through the volume of the data or through the out-of-bounds nature of the its content. Pen testing usually runs alongside other DAST tool techniques to detect runtime errors when fuzzing the application’s inputs.
DAST tools require a running application in order to work but can find different classes of vulnerabilities from SAST (just as SAST can find vulnerabilities in code not normally executed during dynamic testing) and complement each other.
A commonly used term, vulnerability testing, refers to the discovery, analysis, prioritization of security vulnerabilities. When looking at application software in particular, the term overlaps with application software security testing so the terms can be used interchangeably. However, there are vulnerabilities at a system and organization level that are out of scope for software security testing so it’s possible vulnerability testing is used outside the scope of application-level security. The classic example is social engineering which is a significant security risk for organizations and you could “test” for it via physical security audits.
Up next, we will publish a blog looking into Software Supply Chain Security terminology.