Static and Dynamic Analysis

Static and Dynamic Analysis Tools

What is static and dynamic code analysis?

During the last years software has become larger and more complicated with many functionalities. These functionalities demand a bigger architecture and more complexity including a large number of modules and interactions. Usually, we work on a project from a few developers to a couple of teams. It means that the probability of having bugs is increased. We can not rely on a single-onetime activity to find them. We have to employ different approaches such as using tools, processes, etc. One of the easiest ways to discover potential flaws is using static and dynamic code analyzers. By setting them up in a CI environment we ensure that automatically and continually our code is being checked against some levels of known problems. In continue we look into them.

Static Code Analysis

Nowadays some IDEs include code analysis tools such as static analyzer, dynamic analyzer, dependency analyzer, etc. Each tool can be used to inspect the code to find the probable flaws or vulnerabilities from stack overflow to some more advanced ones. Though they can not discover all the problems utilizing them is a big step toward more secure software. The better solution can be a mix of commercial and open-source analyzers locally or in CI/CD.

Some of the features are included in the static code analysis listed below:

  • Control Flow Graph
  • Code complexity
  • Code style
  • Dead Code Detection
  • Error Detection (buffer overflow, dereference null pointer, etc)
  • Resource leakage
  • Type checking
  • etc

Lint or linter is a static analysis tool that can discover potential flaws, bugs, etc. We can find a lint for most programming languages. Some of them are listed below:

C/C++

  • CppCheck
  • Clang-Tidy
  • cpplint

Java

  • SonarQube
  • CheckStyle
  • FindBugs

Kotlin

  • Android Lint
  • IntelliJ IDE

Python

  • Flake8
  • Pylint
  • PyCharm IDE

These tools check for patterns or well-known bugs in the code that could result in security issues like buffer overflows, SQL injection, or command injection vulnerabilities. Static code analysis is frequently more effective than dynamic analysis and can cover a wide range of code in a short period because it does not require the execution of the code.

Due to the size and complexity of Android apps, static analysis is especially helpful in developing Android software. There is a considerable chance of introducing vulnerabilities into the code because of the numerous third-party libraries, the handling of dependencies, and the handling of user input. Static code analysis tools ought to be in every Android developer’s toolbox.

public Connection getUserInfo(String username) {
  try {
    String url = "jdbc:mysql://localhost:3306/mydb?user=" + username ;
    Connection connection = DriverManager.getConnection(url);
    return connection;
  } catch(SQLException e) {
    e.printStackTrace();
    return null;
  }
}

In the above example, a potential security vulnerability for SQL injection exists since the user-supplied usernamestrings are directly concatenated into the connection URL. As you can see, this way of using the input parameter can lead to SQL-injection and the static code analyzer will warn it.

Example – Android Studio Static Code Analysis for Java/Kotlin: Android Studio, the official IDE for Android development, includes a static code analysis tool called Lint. Lint checks the code for potential problems related to performance, security, and other aspects of Android apps.

// main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>


int main()
{
    char argc;
    char argv[20][40];
    char buffer[8];
    if (argc > 1) {
        printf("Usage: %s <input_string>\n", argv[1]);
        strcpy(buffer, argv[1]);
    }
    printf("\nTerminated normally!\n");
    return 0;
}

//cpplint lint_example.c

CppCheck output

cppcheck  --enable=all lint_example.c 

Output

Checking lint_example.c …
lint_example.c:13:10: style: The scope of the variable 'argv' can be reduced. [variableScope]
char argv[20][40];
^
lint_example.c:14:10: style: The scope of the variable 'buffer' can be reduced. [variableScope]
char buffer[8];
^
lint_example.c:15:9: error: Uninitialized variable: argc [uninitvar]
if (argc > 1) {
^
lint_example.c:12:10: style: Variable 'argc' is not assigned a value. [unassignedVariable]
char argc;
^
nofile:0:0: information: Cppcheck cannot find all the include files (use --check-config for details) [missingIncludeSystem]

cpplint output

cpplint lint_example.c 

Output

lint_example.c:0:  No copyright message found.  You should have a line: "Copyright [year] <Copyright Owner>"  [legal/copyright] [5]
lint_example.c:11:  { should almost always be at the end of the previous line  [whitespace/braces] [4]
lint_example.c:17:  Almost always, snprintf is better than strcpy  [runtime/printf] [4]
lint_example.c:23:  Should have a space between // and comment  [whitespace/comments] [4]
lint_example.c:23:  Could not find a newline character at the end of the file.  [whitespace/ending_newline] [5]
Done processing lint_example.c
Total errors found: 5

checkstyle


public class SqlInjection {
	public Connection getUserInfo(String username) {
	  try {
		    String url = "jdbc:mysql://localhost:3306/mydb?user=" + username ;
		    Connection connection = DriverManager.getConnection(url);
		    return connection;
	  } catch(SQLException e) {
		    e.printStackTrace();
		    return null;
	  }
	}
}
java -jar checkstyle-10.10.0-all.jar -c google_checks.xml SqlInjections.java

Output

SqlInjections.java:2:1: The name of the outer type and the file do not match. [OuterTypeFilename]
SqlInjections.java:2:1: Missing a Javadoc comment. [MissingJavadocType]
SqlInjections.java:3:1: Line contains a tab character. [FileTabCharacter]
SqlInjections.java:3:9: 'method def modifier' has incorrect indentation level 8, expected level should be 2. [Indentation]
SqlInjections.java:3:9: Missing a Javadoc comment. [MissingJavadocMethod]
SqlInjections.java:4:1: Line contains a tab character. [FileTabCharacter]
SqlInjections.java:4:11: 'try' has incorrect indentation level 10, expected level should be 4. [Indentation]
SqlInjections.java:5:1: Line contains a tab character. [FileTabCharacter]
SqlInjections.java:5:21: 'try' child has incorrect indentation level 20, expected level should be 6. [Indentation]
SqlInjections.java:5:86: ';' is preceded with whitespace. [NoWhitespaceBefore]
SqlInjections.java:6:1: Line contains a tab character. [FileTabCharacter]
SqlInjections.java:6:21: 'try' child has incorrect indentation level 20, expected level should be 6. [Indentation]
SqlInjections.java:7:1: Line contains a tab character. [FileTabCharacter]
SqlInjections.java:7:21: 'try' child has incorrect indentation level 20, expected level should be 6. [Indentation]
SqlInjections.java:8:1: Line contains a tab character. [FileTabCharacter]
SqlInjections.java:8:11: 'try rcurly' has incorrect indentation level 10, expected level should be 4. [Indentation]
SqlInjections.java:8:13: 'catch' is not followed by whitespace. [WhitespaceAfter]
SqlInjections.java:8:13: WhitespaceAround: 'catch' is not followed by whitespace. Empty blocks                may only be represented as {} when not part of a multi-block statement (4.1.3) [WhitespaceAround]
SqlInjections.java:9:1: Line contains a tab character. [FileTabCharacter]
SqlInjections.java:9:21: 'catch' child has incorrect indentation level 20, expected level should be 6. [Indentation]
SqlInjections.java:10:1: Line contains a tab character. [FileTabCharacter]
SqlInjections.java:10:21: 'catch' child has incorrect indentation level 20, expected level should be 6. [Indentation]
SqlInjections.java:11:1: Line contains a tab character. [FileTabCharacter]
SqlInjections.java:11:11: 'catch rcurly' has incorrect indentation level 10, expected level should be 4. [Indentation]
SqlInjections.java:12:1: Line contains a tab character. [FileTabCharacter]
SqlInjections.java:12:9: 'method def rcurly' has incorrect indentation level 8, expected level should be 2. [Indentation]

Dynamic Code Analysis

Dynamic code analysis, sometimes referred to as dynamic program analysis or runtime analysis, entails examining an application’s behaviour as it is being used or executed. Static code analysis may miss security holes, performance problems, or memory leaks that can be found by dynamic analysis.

To track the behaviour and data flow of the program, dynamic analysis tools execute the application in a controlled environment. To test an application’s reaction to unforeseen circumstances, these tools also attempt to modify user input or other external causes.

As it can infer the behaviour of the application during execution and therefore identify vulnerabilities that might not be obvious in the static code, dynamic analysis is more powerful than static analysis. However, dynamic analysis might take longer and require more resources than static analysis.

Some of the features are included in the dynamic code analysis listed below:

  • Runtime error detection
  • Input validation and fuzz testing:
  • Performance profiling
  • Memory profiling
  • Race condition detection
  • Security vulnerability detection
  • API monitoring and testing
  • Load testing and stress testing
  • User experience testing
  • etc

C/C++

  • LDRA
  • Valgrind

Java

  • JRat

Kotlin

  • Android Studio

Android

  • Drozer

Python

  • DynaPyt

Dynamic analysis in Android development can assist in identifying problems that may not be seen during static analysis, such as runtime permissions, insecure network connections, the unsecured storage of sensitive data, or vulnerabilities in third-party libraries.

Example of Dynamic Code Analysis in Android:

Assume a scenario where an Android app stores sensitive user information, such as login tokens, in SharedPreferences:

SharedPreferences sharedPreferences = getSharedPreferences("MyApp", Context.MODE_PRIVATE);
sharedPreferences.edit().putString("user_token", loginToken).apply();

This code might not cause any issues to be discovered during static code analysis. Dynamic analysis, however, may show that attackers with physical access to the device or even other programs can access the information that has been stored. This event serves as a reminder of the need to securely storing sensitive information using encryption techniques like the Android Keystore system.

To ensure secure coding methods, especially in Android development, static and dynamic code analysis are vital. While dynamic code analysis assesses the behaviour of the application during runtime to find security flaws that may not be obvious in the static code, static code analysis aids in the detection of potential issues and vulnerabilities in the source code. Developers can create secure Android applications and reduce security risks by combining both of these approaches with the appropriate tools.

Link to Book: Secure Android Development: Best Practices for Robust Apps

Leave a Comment

Your email address will not be published. Required fields are marked *