How do we detect vulnerabilities in our Web Applications?

Laurent Delosieres
ManoMano Tech team
Published in
8 min readSep 16, 2020

Spotting vulnerabilities in your Web App before they get exploited by an attacker is definitely a complex problem. Different technologies have been introduced in the market to ease the work of security software engineers - SAST, DAST, and RASP. Those tools intervene in different states of the pipelines, and run different checks, but they all share the same purpose: detecting security vulnerabilities while minimizing the number of false positives. Minimizing the false positives is an important criteria in order to prevent the tool from being rejected by the developers. In this article, we will share with you our insights about the three technologies (pitfalls and pros) before revealing what ManoMano has opted for.

SAST, DAST, and RASP: what are they ?

SAST or Static Application Security Testing

The SAST or Static Application Security Testing parses the source code of a project and outputs all the security violations (e.g. deprecated hashing functions, etc). Depending on the maturity of the tool, the SAST can also identify the parameters that can be controlled by an attacker, but this method results in many false positives or false negatives. To determine if an attacker- controlled parameter can be injected into a vulnerable function, the SAST will first need to taint the input variables that are passed by the attacker (e.g. GET parameters). Those functions are called source functions because they are producing the tagged variables. If a tagged parameter reaches a sink, e.g., the “query()” function of a database, a critical path has been identified and there is potentially an exploitable vulnerability. Whenever a tainted variable passes through a sanitizing function, the resulting variable is untainted.

Figure 1 shows an excerpt of a SonarQube check linking the source “$_GET[“id”]” to the sink “$mysqli->query($sql)”. Since a path exists between the source and the sink, an SQL injection can be exploited by an attacker.

Figure 1 — SonarQube excerpt highlighting an SQL injection

However, the SAST has some limitations:

  • the non exhaustive list of sources / sinks / sanitizers
  • the timing performance
  • the wrong inference between tagged variables
  • bad assumptions of the sanitizers

The first limitation that we stumbled upon was the incomplete lists of sources / sinks / sanitizers. Some SQL injections were not identified due to the sources not being calibrated to our framework. For open source tools, those lists can be adjusted, but for closed source tools, it is out of the control. Additionally, calibrating the tool requires some heavily tests of the framework.

The second limitation comes from the timing performances. Analyzing the whole code, i.e. transforming it into an Intermediate Language, tagging the variables, and building up paths between sources and sinks is a tedious task that can take up to several hours. In a nutshell, this is a process that cannot be easily embedded in the CI except if the tagging feature is disabled or only operates on the new code, but again this does not guarantee the soundness of the checks.

The third limitation is due to the bad inferences between input and output variables when handling string concatenations. Many false positives were triggered due to the concatenation between a hard-coded string and a tagged variable. For the SAST tools, it is not trivial to know whether a concatenation of strings will still be exploitable by an attacker or not. If the developer explicitly calls the sanitizing functions, the tool will correctly interpret the results. But this is not always the case, especially with the legacy code, which becomes a nightmare for the security software engineer that needs to sort out the tremendous number of false positives.

The last limitation stems from the sanitizing functions themselves. In some SAST tools, when a tagged variable passes through a sanitizing function, the outcome variable is untagged, but this is not always true. For instance, a sanitizing function might sanitize a variable against XSS (Cross-Site Scripting) attacks but not against Path Traversal attacks. It would be too naive to make this assumption.

DAST or Dynamic Application Security Testing

The DAST or Dynamic Application Security Testing as its name suggests requires performing the tests on a running instance, meaning those checks cannot be performed in the CI pipeline but only in the CD pipeline. A battery of tests are launched against the new instance, and the tool determines whether or not e.g. a parameter is subject to SQL injections. Launching those tests usually take some minutes up to some hours before getting the results. However, those tests do not generate so many false positives like the SAST tool. In a nutshell, when a parameter is injectable, a pen-tester can easily confirm and exploit the vulnerability. Unlike the SAST tool, the DAST does not need to know what is beneath the web application, e.g., framework, programming language, etc. However, the engineer is required to list all the endpoints along with the accepted parameters to be able to build up an exhaustive list of tests. In Figure 2, the DAST is discovering an SQL injection in the framework.

Figure 2 — DAST detecting an SQL injection

RASP or Runtime Application Self-Protection

The RASP or Runtime Application Self-Protection is a new technology, which is not very well known but very efficient. The paradigm consists in considering that no security tests are exhaustive enough. Instead of launching several tests in the CI/CD pipeline, the critical functions, i.e., sinks functions are protected in real time. When the parameters contain malicious content, the RASP achieves two functionalities: it (1) blocks the request before it reaches the sink and (2) alerts the security team that a sanitizing function is missing. The WAF or Web Application Firewall is slightly different, as it analyzes the HTTP requests and not the parameters passed over to the functions. This implies that the WAF usually generates more false positives, and thus forces the engineer to spend more time during the calibration phase before enabling the blocking mode.

The RASP comes with an extension which is loaded by the framework. During its first instantiation, the extension will look for the critical functions of the framework and hook them. Whenever a critical function is called upon, the hook will be executed first and will test the parameters against a set of rules. If there are no matches, this implies that the parameters are not controlled by an attacker and thus, the parameters can be safely handed over to the critical functions. Most of the time, those rules are coded using regular expressions. To speed up the compilation of those regular expressions, the compilation of the regular expressions are occurring at the first instantiation using the native functions of the framework. For instance, a PHP module will (1) locate the regex function of the PHP framework, (2) compile the regular expressions, and (3) re-use the compiled versions.

RASP and WAF are very similar in the way they are checking the parameters, but since the checks are performed at different levels, the performances differ. Indeed, the WAF will verify any malicious content inside an HTTP request whereas the RASP will check the presence of any malicious contents in the parameters passed to a critical function. Since the parameters are decoded, the RASP is less subject to false positives. This can easily illustrated with the following examples.

Example: “query” parameter in an encoded URL analyzed by the WAF

Example: same “query” parameter analyzed by the RASP

Furthermore, when a URL contains a blacklisted keyword such as “index.php?query=select product”, a WAF will very likely trigger a false alert due to the presence of the keyword “select” although the request is legitimate. Unlike the WAF, some RASPs embed a semantic SQL analyzer which benefit from a higher context, i.e. the analyzer knows the database model, the full SQL query, the stack trace, and the decoded parameters. By combining the context plus the semantic of all the SQL parameters, the analyzer is able to detect SQL injections with a better accuracy.

However, the RASP presents some drawbacks: (1) to be efficient, the sink functions of all the existing drivers / frameworks (e.g. MySQL, Symfony, etc.) need to be hooked and (2) hooking a sink function is harder than just adding a regular expression in the WAF. And this is where the framework Sqreen comes in by combining the strength of both the WAF and RASP — when the WAF does not catch the attack, the RASP does and vice versa.

Sqreen

Instead of adding an external WAF, Sqreen provides its own In-App WAF which is based on a set of regular expressions that protects the app from the easiest attacks besides the RASP that blocks the most complex attacks. By finding the right balance between the attacks that are blocked by the In-App WAF and the RASP, Sqreen achieves very good performances in terms of detection rate versus false positive rate. See Figure 3 for the list of attacks covered by each module (In-App WAF and RASP).

Figure 3 — list of attacks covered by each module

Nevertheless, Sqreen is more than just an InApp-WAF + RASP, it also enables the security engineer to tweak Content Security Policy and Security Headers up dynamically by updating HTTP headers on the fly such as anti Click-jacking, MIME sniffing, XSS protection, and Application Referrers to the HTTP headers and implements a User Monitoring. In a nutshell, Sqreen is a defense in depth framework with several layers of protections as shown in Figure 4.

Figure 4 — Sqreen’s defense in depth

When most of the commercial solutions offer to ban malicious actors by their IP, Sqreen proposes both IP banning and User banning based on a list of Playbooks. Thanks to its SDK, the engineer has the possibility to track the actions of their customers on their WebApp, e.g. login, checkout, and block them if their behavior is abnormal based on a playbook. For instance, a user IP stemming from the TOR network might be suspicious, or a takeover of an account should trigger an alarm. When a playbook is triggered, the user can be blacklisted for a limited / unlimited duration from the application.

During the check of the presence of malicious content inside a parameter, Sqreen might take some time depending on how big the list of regular expression is. To control the response time of the web application, Sqreen monitors the time spent in each module (RASP + In-App WAF). Additionally, it allows the security engineer to bound the analysis time by fixing a time capping per request. If it exceeds a certain threshold, the request will be marked as partially analyzed in the dashboard.

Conclusions

At ManoMano, we always prefer embedding innovative technologies than just copying everyone’s else security frameworks. We are wondering which technology you are using to detect vulnerabilities and if you had any previous experience with a RASP.

--

--

Laurent Delosieres
ManoMano Tech team

Security Software Engineer at ManoMano. Laurent is passionated by all the cybersecurity challenges ranging from reversing to exploiting