GraphQL security for decentralized applications (DApps): challenges and best practices
Apart from the issue of poor user experience, security is one of the greatest setbacks to global Web3. Blackhats are constantly exploiting Web3 applications to siphon funds. On the 2nd of July, 2023, Poly Network lost about $5 million to a hack. Atomic Wallet lost over $100 million to a breach in June 2023. Jimbos Protocol also lost over $7 million to a security bug.
But there is a big misconception about the state of DApps security: most people think breaches happen only on smart contracts. In fact, breaches also happen at the application layer of a DApp.
For example, MyAlgo Wallet lost over $9 million to a Cloudflare key compromise on the 27th of February, 2023. Recall how CoinDash lost approximately $8 million to a front-end attack in 2017. Perhaps give two more examples. An attacker also used a front-end injection attack to steal $2 million from MM Finance in 2022.
It’s clear that good old HTTP APIs are a huge, often overlooked, attack vector for DApps. More specifically, DApps rely increasingly on GraphQL, a new API technology that supports decentralized data aggregation, to expose their blockchain to applications. But this technology comes with specific security risks that malicious users could exploit in many ways. For these reasons, understanding GraphQL security is important for DApps developers and security professionals.
In this blog post, we will examine the challenges of GraphQL security for DApps, and its best practices. This is a must-read to level up your game of writing battle-tested databases and APIs.
TL;DR
- Threat actors can breach Web3 security not only from smart contracts alone but also APIs.
- GraphQL has several security challenges, such as code injection attacks, insecure data handling, automated malicious attacks, and Denial of Service (DoS) threats.
- Incorporating certain best practices such as rate limiting, proper validation, query depth restrictions, and simplified API discoverability is highly recommended. These measures ensure optimal performance, security, and user-friendliness for your API.
Challenges of GraphQL security in Web3 applications
Once you have built the smart contract behind your DApp, you will need GraphQL to query and get data from user activities. Although GraphQL is a relatively new query language and offers some advantages over REST API, it is still prone to some vulnerabilities common to some other query languages.
Security is of utmost importance in Web3 as attackers are continually looking to take advantage of vulnerabilities in the system to gain access to people’s wallets, manipulate transactions and steal funds.
However, if properly implemented, GraphQL offers more backend stability and efficiency. This section will examine security concerns that Web3 applications supporting GraphQL should acknowledge.
Injection attacks
An injection attack is a very common type of attack on an API, as they are not peculiar to GraphQL alone. In this attack, an attacker sends a malicious input to an API with a parser or interpreter that processes the inputs before passing them to the backend system or database.
If the parser does not properly validate the input, the attacker can gain access to or manipulate some confidential information. This is something to be extremely careful of in Web3 applications, as attackers can use these attacks to sign transactions maliciously.
In addition, GraphQL uses JSON format to encode data requests, and this format can enable a malicious request to bypass some protections.
Multiple calls per request
A downside of GraphQL is how it allows multiple function calls within each request. This feature is called "batching" or "aliasing." This is one of the most common security challenges in GraphQL.
The implication of its inability to take multiple actions is that no specific amount of server resources is prepared beforehand. For instance, a malicious user can send multiple requests in one function. Let's take a look at the example below.
mutation GainAccess {
g00000: secretKey( input: { secret: "secret_guess_0"}) {
balance
},
g00001: secretKey( input: { secret: "secret_guess_1"}) {
balance
}
.........
g99999: secretKey( input: { secret: "secret_guess_99999"}) {
balance
}
}
In the example above, we can see a malicious attempt to gain access to a user's balance by sending multiple requests, with each request guessing the secret of the account.
Let’s take a look at another example:
query Recursion{
allTransfersToAddress{
address{
recipient {
address{
recipient{
address {
recipient{
address
}
}
}
}
}
}
}
}
Here is an example of a user trying to query the address of some token that was sent to, which has also sent some token to another address, and so on and on. Although it looks quite simple, it is complex. Adding another layer of query further compounds its complexity.
Insecure data mapping
GraphQL provides legitimate users with direct access to data through its API, a feature that, while valuable, can be exploited by attackers.
This direct access allows legitimate users to interact with the data precisely and efficiently. But if the application using a GraphQL API is not properly secured, an attacker could exploit this same direct access to carry out extensive data extraction from the system.
Also, GraphQL’s flexibility allows users to specify the response format to their requests. An attacker can manipulate this feature to define requests that a traditional Web Application Firewall (WAF) cannot detect the hidden attack.
Automated Attacks
With the advent of bots, there has been a growing threat to web application security and usability. In 2019, malicious bots accounted for about 30% of all internet traffic. In Web3, new bot threats arrive every day, ranging from bots-as-a-service to NFT-hoarding bots.
These bots are mostly used for fake account creation frauds and credential stuffing. Malicious attackers use bots to exploit GraphQL APIs, including spamming, data scraping, and executing custom queries.
It is crucial to block malicious bots from consuming your GraphQL API while granting access to search engines to scrape your app for indexing purposes. Hence, it becomes a challenge to balance security and utility.
One of the biggest threats bots have on a GraphQL application is Denial of Service (DoS) Attacks. Here, an attacker can use a bot to send a query that exceeds the query depth level or maximum size that the application can process and then cause the application to crash—as a result of this, rendering it incapable of receiving and processing legitimate requests.
GraphQL Security Best Practices in Web3
While GraphQL does have some vulnerabilities, you can implement some of these best practices for your decentralized application (DApp) to be more secure:
Rate limiting
One effective way of doing this is using query timeouts. By using this method, you are setting a limit to how long a single query can be executed. This method effectively limits the operational window of the malicious attacker.
Limit query depth
Managing query depth (i.e., the number of nesting levels of the field) is a critical consideration for GraphQL. Limiting query depth to a specific level effectively reduces the risk of an attacker sending malicious queries that could potentially shut down your server. This practice is a barrier against harmful requests that could overload your system, contributing to a robust defense against Denial of Service (DoS) attacks. Many GraphQL implementations come with a specific parameter that you can set to a designated value. When this value is set, any queries beyond this depth level are automatically disregarded by the GraphQL engine without initiating the evaluation process.
Limit API Discoverability
In GraphQL, the introspection feature is enabled by default. While this may pose a vulnerability risk—allowing threat actors to access sensitive data through the GraphQL schema, including types, fields, and directives—simply turning it off may not enhance server security in practice. How do you limit your API discoverability through the introspection feature? Set up your GraphQL server to allow introspection only for certain user roles, like administrators or developers. This ensures that only trusted users have access to this feature.
Proper Validation
Input validation and sanitization are standard web practices. Proper input validation should happen as early as possible in the data flow. Without revealing too much information, you should reject invalid inputs right away. You can also leverage GraphQL schema to support input validation. You can learn more about input validation and sanitization approaches in this article.
Conclusion
In the rapidly growing space of decentralized applications (DApps), GraphQL is a key technology that enables efficient data retrieval. It’s a vital part of the modern Web3 architecture, but its convenience comes with potential risks.
Web3 companies must prioritize GraphQL security to protect against vulnerabilities that can lead to significant financial loss, data breaches, and damage to the company's reputation.
By following best practices such as proper input validation, limiting query depth, and keeping APIs updated with the latest security patches, you can mitigate many of the risks associated with GraphQL.
Need a complete and automated security solution for GraphQL APIs? Or just want to see the list of exposed APIs in your DApps? We've got you covered.
Escape can help you build a comprehensive inventory of all your APIs, including GraphQL, REST, and gRPC. You can easily try Escape by signing up for a free account to find your vulnerabilities before committing.