When the foundations break, the building crumbles. Applications are no different. When building an application, you need to choose the best building blocs. They need to be durable and upgradable so they can keep up with technology.
Dependencies can be very practical, as they help you achieve big tasks with a minimum of effort. But, including a malicious or a vulnerable dependency in your project can lead to its demise. This guide helps you keep the balance between practicality and security. How to choose dependencies while maintaining your application’s security.
What are dependencies
Source code dependencies are external libraries that your project relies on to function. These can be frameworks, or packages that are external to your project.
The dangers of insecure dependencies
When you add a dependency, your package manager downloads it and adds it to the project’s libraries. You can then import code from that dependency in your project via specific instructions (import PACKAGE_CLASS
).
The compiler replaces the import instruction with the code from the referenced dependency. So, importing a dependency is like copy/pasting the dependency’s code inside your own project. 2 main risks sprout from this:
- If a dependency contains malicious code: that malicious code will find itself inside your project. Imagine a dependency that has instructions to send application configuration to a remote server. If you import that dependency, the attacker receives your project’s configuration. The leaked data might include API keys and database credentials. The dependency can also get your client’s credentials, credit card numbers, environment variable, and more. This kind of attack is very common, and regularly identified by researchers.
- If a dependency is vulnerable: your project inherits that vulnerability. Let’s take a dependency that does image processing as an example, and you use it to resize images sent by users. Imagine that attackers can, via a crafted image file, force the dependency to execute system commands. Users of your application can exploit that vulnerability in your project. They can use that same malicious image file to force your server to execute their command. You inherited the vulnerability, and your application can get compromised because of it.
So, a dependency has the power to compromise your application. Don’t give that power lightly, and choose your dependencies carefully.
Cleaning out your closet
To protect ourselves, we will sort our dependencies to avoid including untrustworthy ones.
Delete unused dependencies
Go through the dependencies installed by your project (in the file pom.xml), and see if your project source code uses every one of them.
If you find a dependency that is not imported anywhere in your project, delete it. This will reduce the attack surface and thus decrease the risk of a compromise.
Vet your dependencies
The list of used dependencies will go through a vetting process to see if they are worthy of our trust. The process is many fold:
Step 1: Did you spell it correctly?
We all occasionally suffer from a fat finger incident. You want to type one character but end up hitting a different key on the keyboard resulting in a typo.
As benign as that seems, it can become a security threat. When you manually type the name of a dependency, you risk making a typo. The best case you can hope for is that this erroneous dependency name does not exist, and maven will return an error message telling you so.
But, some smart hackers took notice, and decided to “typosquat” famous dependencies. They created malicious maven packages that have names very close to popular packages. For example, org.springfamework
instead of org.springframework
. If you make that typo, the harmful dependency gets added to your project and your application gets compromised.
To avoid this issue, make sure to copy/paste the names of dependencies from trusted sources.
Also, check the dependencies you are already using. Make sure they point to the real dependency that you were intending to use.
Step 2: Is the publisher trustworthy?
Here, we will be looking at the entity that created and is maintaining the dependency. For each one, we will ask ourselves 2 questions:
- Is the publisher security aware? Compromising the publisher’s account allows attackers to introduce malicious code into a dependency. Thus, the more security aware the publishing entity is, the safer the dependency. If the publisher is an ordinary person, the dependency has a higher chance of getting compromised. Hackers can attack his computer, github, or email to introduce harmful code into his dependency. So be sure to use dependencies published by known companies or by people with an authority in the development space. A dependency published by Google is less likely to get compromised than a dependency published by James Clipon.
- Is the publisher trustworthy? An independent person publishing a dependency is also more likely to have a malicious intent behind him than a big corporation. With the anonymity offered by dependency packagers, anyone can create a new identity and publish a dependency. A hacker can create dependencies that are helpful, but containing malicious code. This behavior is much less likely coming from a big and known corporation. Such a risky move can give a big blow to the trust they try to build with their customers. Prominent figures in the development space are also less likely to engage in such behavior to avoid any credibility damage.
If the answer is no for any of the previous questions, then it is better to search for an alternative.
Step 3: Is the dependency actively maintained?
If the publisher hasn’t updated the dependency in over 6 months, you should find a different one.
The dependency’s own dependencies might suffer from security vulnerabilities. A maintainer should be ready to quickly update the project if a vulnerability arises. If the project is not actively maintained, a published vulnerability on the project can go unpatched for a long time. This gives attackers ample time to exploit it in your application.
Scan your dependencies
Before deploying your project, scan your dependencies for any publicly disclosed vulnerabilities. You can use the Maven plugin dependency-check-maven for this.
Update the dependencies to get rid of all the vulnerabilities identified. You should automate this step in your deployment process (via SonarCube or other CI/CD tools you are currently using). If the scanner identifies critical or high risk vulnerabilities, abort the deployment.
Leave a Reply