SAST stands for Static Application Security Testing. It's a form of white-box testing in which your application's source code is scanned for potential vulnerabilities. Writing Clean Code can help to ensure your application is free from these vulnerabilities and using SAST helps to detect issues as you build.
When you use SonarQube or SonarCloud to analyse your source code, it uses static analysis to detect issues in your code that cause bugs and security vulnerabilities. There are two types of vulnerabilities that Sonar scans for:
- Injection attacks, like:
- Configuration vulnerabilities, like
Configuration vulnerabilities are often due to mistakes like using the wrong parameter when calling a sensitive function, whereas injection vulnerabilities are a bit more tricky.
Injection vulnerabilities are detected by a technique called taint analysis. Taint analysis determines whether potentially malicious user input makes it through your application to a sensitive output like a database or file system, or if it's used by the front end to generate the user interface.
Taint analysis detects the following in your application code:
- User inputs to a system (sources)
- Functions that make user input safe (sanitisers)
- Functions that check to see if user input is safe (validators)
- Sensitive functions that receive user input and could be exploited (sinks)
Once the analysis understands the sources, sanitisers, validators, and sinks in a system, it can track the user input from the source and ensure that it is either sanitised or validated before it is used as an argument to a sink. If user input makes it through to a sink without being sanitised or validated, then you have an injection vulnerability in your code.
Let's see what this means in practice in a code base. Here is an excerpt from an Express application with a route that dynamically returns a file from the filesystem based on a query parameter. The code is intentionally simple and vulnerable to a path injection, also known as a directory traversal, attack.
The SonarCloud analysis of this code looks like this:
SonarCloud detects a source in
server.js: the user controls the incoming HTTP request, so we cannot trust it. The user input is passed to the
getImages function, which is concatenated with other data using the path module's
join function. The resulting path is then passed to the
createReadStream function, and the file contents are streamed to the response object and back to the user.
Because we never sanitise or check the data from the user, this code is vulnerable to a directory traversal attack illustrated in the SonarCloud analysis. The code is supposed only to read files from the images directory, but if you, for example, pass a filename like
"/images?filename=../package.json" then you will get back the project's package.json file. You can run this application and try it yourself with the source code available on GitHub.
This is a relatively simple issue, but it can be challenging to keep track of it in your head when user input passes through more functions and more files. That's where SAST comes in.
node_modules directory, you will know intuitively that scanning all of those dependencies would be terrible for the performance of the scanning process.
However, we may miss out on potential vulnerabilities by treating our dependencies as safe black boxes. To counteract that, Sonar now pre-scans popular open-source libraries to find sources, sinks and sanitisers and makes that data available to our taint analysis engine. Sonar's taint analysis can then better understand the interactions between your code and your dependencies' code gaining a greater understanding of how user input enters your application, flows through it, and where tainted data might exit causing a vulnerability. Notably, deeper SAST does not look for vulnerabilities in the dependency code, instead, it finds interactions that can make your code vulnerable.
Deeper SAST enhances Sonar's taint analysis with deep knowledge about your dependencies to uncover hidden vulnerabilities.
One of the dependencies that we now scan is
fs-extra. This library wraps Node's
fs module and adds extra file system functionality. You can use
fs-extra as a drop-in replacement for fs, any function that
fs-extra doesn't implement is passed on to fs. These are the changes I made to the code:
As you can see, I have only changed the imports. The actual code has stayed the same, but with traditional SAST the vulnerability would no longer be detected.
Now with deeper SAST, the vulnerability is caught just like the direct call to the
fs module. All the additional
fs-extra functions are also covered, so path traversal vulnerabilities will be detected when using potentially dangerous functions like
In the above screenshot, we see the results of scanning a file called
image-fs-extra.js. This file is using
fs-extra instead of the
fs module and the vulnerability is still caught. You can check out the full source code of this project on GitHub and see the analysis results in SonarCloud.
Avoiding injection attacks is a case of understanding how user input flows into and through your application and always sanitising or validating it before it is sent to sinks like functions that deal with the file system or databases. SAST can help you detect these application issues by tracking tainted data across functions and files. Deeper SAST goes further by understanding popular open-source libraries and their sources of tainted data or potentially vulnerable sinks.