AppSec Tip #1: Know your building blocks

Mohamed AboElKheir
AppSec Untangled
Published in
5 min readJun 21, 2023

Leaky Abstractions

One piece of advice I got from a senior developer early on as I was starting my career (at this point I was a Linux SysAdmin) turned out to be very useful especially later on when I got into the “Application Security” field.

He told me that being a good developer is not just about knowing how to write efficient code, as it is equally important to understand reasonably well all the underlying building blocks the code is running on including the Hardware, Operating system, libraries and packages (dependencies), network protocols, databases, frameworks, .. etc and how they work.

As time went by I found this to be more and more true, as during my different roles I found out that a big chunk of the issues and bugs found in the software was caused by issues related to these building block or to how the code interacts with them, rather than a logic issue in the code itself.

Code needs building blocks to run

The reason for that is that applications are complex and have a lot of building blocks, and obviously, it is not realistic or efficient to expect developers to know everything about all these building blocks. Hence, most of the time developers are using libraries or tools to abstract the actual interaction with these building blocks (e.g. using the Python requests library to send an HTTP request, or using Flask for an HTTP server) , which makes it easier for them to focus on the actual logic their own code, and makes development easier and faster. However, if the developer doesn’t understand the building blocks behind this abstraction, the way their code interact with it can introduce issues and bugs. Later on, I found there was a name of this concept which is Leaky Abstraction.

This shouldn’t be misunderstood as discouraging developers from using this kind of abstraction, but rather encouraging developer to better understand the building block behind the abstraction, which can help them create applications with better performance, and fewer bugs and issues.

How this applies to “Application Security”

Fast forward a few years, and I am now into the “Application Security” field, and what I have found is that the same concept applies even more to creating secure applications, as in my experience also a lot of the security issues and vulnerabilities also relate to these building blocks that applications are using, but developers sometimes abstract without fully understanding. In other words many security vulnerabilities are manifestations of the leaky abstractions mentioned above.

Example1: The Log4j vulnerability

Let take as an example the CRITICAL Log4j vulnerability (CVE-2021–44228) that took the internet by storm not too long ago. Log4j is a very widely used library used by Java developers to handle logging, and because of a feature Log4j supports which most of of the developers never used and may have never heard of (JNDI lookups), their applications were vulnerable to remote code execution.

Log4j leaky abstraction caused RCE

Example 2: SQL injection

Another example is the “SQL injection” category of vulnerabilities. If your application is using an SQL database, then you need to run queries and statements on this DB, and this is typically done through using a library that runs these queries and statements. Using this library makes things easier for developers, but unless they make sure they are using this library securely, user input can end up tricking the library running other queries and statements which can lead to unauthorized data exposure, tampering or even remote code execution. (For more information about SQL injection you can watch https://www.youtube.com/watch?v=WWJTsKaJT_g)

Libraries used to run SQL queries is another leaky abstraction that can cause SQL injection

Add to that the common misconfigurations affecting different kinds of building blocks like:

  • Making an S3 bucket with sensitive data public
  • Deploying an application on Tomcat and making the manager console accessible from the public internet with default or weak credentials, allowing attackers to deploy malicious applications.

The common thing here between all of these vulnerabilities is that they are not related to the code being written by the developers but instead they are related to the configuration of the building blocks they are using or how the code is interacting with these building blocks.

How to address these security issues

Understanding how the building blocks affect the security posture of the application is the first step in being able to create secure applications. Once this is established, here are a few suggestions that can be used to reduce the risk in the different stages of the SDLC (Software development Life cycle):

  • During Design phase, research the underlying building blocks being used by your application, e.g. read the documentation, especially the “Security” section.
  • Create a “Threat model” for your application, and your threat model should include known and unknown vulnerabilities affecting your building blocks in the list of threats.
  • Known vulnerabilities can be mitigated by patching and following best practices in configuration.
  • Unknown vulnerabilities risk can be reduce by following least privilege principal, input validation and avoiding passing different kinds of user input to un-necessary components (e.g. The Log4j vulnerability mentioned above can’t be exploited if no user input is being added to log messages passed to Log4j).
  • During implementation, use libraries and tools that are secure by default (e.g. React isn’t by default vulnerable to XSS) or at least have well defined best practices that mitigate the common security issues.
  • Have a periodic patching plan for your dependencies.
  • Periodically monitor your building blocks for misconfigurations (e.g. monitor public s3 buckets).
  • Add integrations tests or canaries to make sure that future code changes don’t break the mitigations to the threats related to the building blocks you decided on when you created the threat model.

Conclusion

Applications today are complex and need a lot of building blocks to work, hence a lot of abstraction needs to be used to make the development process faster and more efficient. However, abstraction shouldn’t be trusted blindly as it could “leak” different kinds of data and access causing security vulnerabilities. Hence, developers need to have enough understanding of these building blocks, how to use them securely, and how known and unknown vulnerabilities affecting these building blocks affect the security of their application.

--

--