Given the increasing threat to the security of IT application systems, software testing is expected to uncover the majority of potential security vulnerabilities. But dynamic testing is not the only way to discover security flaws in the system. Static analysis of the code can be an inexpensive method of uncovering potential security threats. Not all, but some of the potential security flaws can be detected in this way. (Examples used here refer to Java)
Static analysis is one of many testing approaches to find defects in a software system. It is a technique for examining the requirements texts, design models and code components associated with a software product without actually executing the product. Design reviews and code inspections are based on the same principle, only they are performed by humans. A static analysis is performed by an automaton that checks for various rules. The goal is to uncover defects in the design of the software before the dynamic test.
There are now many tools available for the static analysis of source code. When selecting a suitable tool, the question arises as to the types of defects that are reported by the tool. Another question is the frequency of false reports, so-called “false positives”. These are reports of defects that are not actually real defects. If tools produce many such reports, this only distracts from the real defects. As far as real defects are concerned, it is important to have a classification scheme. From a code security perspective, there are five main classes of defects: Missing Code, Unauthorized Code, Tamperable Code, Error-prone Code, Non-compliant Code.
An example of missing code is the missing check of the input parameters of public methods. The first check is whether the input data has the correct type and whether it is within the valid value range. If not, an exception condition should be triggered.
The same applies to return results. Values returned by called methods in remote classes should be checked before they are used.
Another example of missing code is the absence of the “final” clause in a class definition. The fact that the following class is not declared with “final” allows an intruder to copy and manipulate the code. To prevent this, all subordinate classes should be declared with “final”.
At least one third of the code should consist of security-checking instructions. If this is not the case, it is a sign that the execution of the code is not secure.
Built-in constants are an example of unauthorized code. Having such values in the code is not easy to maintain and is dangerous. Hackers who gain access to the byte code can change these values. It is therefore advisable to outsource all constants to external resources. This is especially true for texts.
Other examples of problem areas are casts and nesting.
One example of manipulable code is built-in SQL statements. They are susceptible to SQL injection attacks, which allow external parties to corrupt the database content. SQL statements therefore have no place in the application code. If they are used at all, then only in a protected access layer.
Further examples of manipulable code can be found in the areas of cloning and deserialization.
Error-prone code can easily lead to an error under certain circumstances. Typical examples of this type of flaw are the comparison of an object with a string or a recursion without an end condition. In terms of security, a potential security vulnerability exists if the number of parameters in the function call is less than the number of parameters in the called method. In this case, the intruder has the opportunity to append their own data to the parameter list and thus spread viruses in the code.
Non-compliant code involves deviations from a given standard. This is not a direct threat to security, but in some cases it could become one. Let’s take the example of when certain standard services are to be avoided because they may be corrupted. If you use them in your code anyway, you run the risk of adopting infected objects.
A study was conducted at North Carolina State University with three million lines of C++ code by Nortel Networks Corporation to show how effective automated static analysis can be. Using the “Flexlint” tool, the experiment uncovered more than 136,000 defects, or one defect for every 22 lines of code, even though the code had been in use for more than three years. The number of defects from the static analysis correlated with the number of error messages from the pre-release test with an accuracy of 83%. This indicates that the errors could have been detected just as well by the static analysis. In contrast to the dynamic test, which cost 12 person-months, the static analysis would only have cost 2 person-months.
As the study shows, the majority of defects can already be detected in the code before testing takes place. This also applies to security defects, but not to other non-functional defects such as time consumption, data volume and throughput capacity. Tools that support testing can be easily integrated into the development process (e.g. continuous integration). In the age of agile development and the continuous delivery of software, defects must be detected and eliminated quickly and without great effort. Static analysis of the code is the best way to do this.
The following list is an example of the rules implemented in such tools. They originate from the JavAudit tool:
Experience with static code analysis shows that many security flaws in an IT system are already visible in the code. Static analysis is an inexpensive, fast and reliable way to uncover these security flaws. Developers only need the right tools and the determination to produce clean code.