This content originally appeared on DEV Community 👩💻👨💻 and was authored by Thomas Hansen
A month ago Oscar posted about how he hacked BeReal, by bypassing the business logic BeReal had implemented on the client, and injected his own business logic - BTW, nice dog Oscar :D
Oscar succeeded because BeReal created their product using Firebase, which of course makes it very tempting to write business logic on the client, the same way GraphQL makes it tempting to put business logic on the client. When the client is responsible for applying the business logic, you basically have zero security for reasons Oscar explains in his article. I like to refer to it as follows ...
Business Logic Injection Attacks
And, this is a problem with not only Firebase, but also Hasura and Supabase. For junior developers looking to "create something beautiful" of course, implementing everything in frontend JavaScript code, and using GraphQL to access the server, sounds very tempting. However, this is for all practical concerns the equivalent of drilling a hole in the boat you're sitting in. It's madness!
There exists methods to secure GraphQL, Firebase, and PostgREST of course, such that injecting malicious business logic becomes impossible - However, all solutions basically implies turning OFF GraphQL construction on the frontend client - At which point (obviously) neither GraphQL, nor PostgREST, nor Firebase have much legitimate remaining value proposition left ...
The "solution" proposed by Hasura, which is to implement business logic in Stored Procedures and Database Functions really doesn't deserve a comment to be honest with you. And their remaining "solutions", which is to create your own HTTP REST API, implies you no longer have any value from GraphQL, and you might as well manipulate and retrieve your data directly from your HTTP API, like Aista does - Shameless plug, I'm the CEO of Aista.
Notice, of course, implementing your own HTTP REST API is a solution to the GraphQL business logic injection security threat - However, if you have to write your own business logic HTTP REST API, why use Hasura, Firebase, or Supabase then? The entire value proposition for developers wanting to use these tech stacks, is that they can simply "start churning out JavaScript code / iOS code / Android SDK code, connect to GraphQL, Firebase, or PostgREST, and their apps are done" ...
As the use case with BeReal clearly illustrates, this is not only not a solution, but it's basically the equivalent of putting business logic validation into the hands of your users. Let me illustrate the problem for you in case you don't get it ...
- Create a Facebook post
- Intercept the invocation towards Facebook
- Add the flag "isAd" to your invocation
- Set your budget to 1 trillion dollars
- Set the flag "hasPaid" to true
Congratulations, you're now running a trillion dollar Facebook marketing campaign without paying!
This is a fundamental problem with allowing the client to construct queries, and is not something that can be fixed, without adding code that literally validates every single query you're accepting on the server. At which point of course, the validation logic becomes a "bajillion" times larger than your original codebase, required to get some MVP up running for a frontend app, that seems to be working perfectly initially. Hence, the cost of your "rapid MVP" is that you cannot set it into production, and you'll have to spend possibly 3 times as much time to secure it, before you can publish it.
This is basically a variation of why whitelisting activities the user is allowed to perform is the only way to apply security, and why most security experts will tell you that "blacklisting activities is 'cheese doodles security'" ...
GraphQL, Firebase, PostgREST, Hasura, and Supabase are basically whitelisting EVERYTHING. Implying the only method to secure your "queries" is to start "blacklisting" things, unless you create a 'strongly typed' API and intercepts EVERYTHING you're passing into these service providers before transmitting it to your data storage ...
The solution
In the video below I am proposing how to rapidly turn off GraphQL construction on "the edge" by using Aista Magic Cloud as your own interceptor, for then to hide the JWT token going towards your GraphQL, Firebase, or PostgREST endpoint, and only allowing Magic to access your JWT token, while doing validation in your Magic cloudlet.
With Magic, this should be a simple job, requiring maybe one or two days to fix. To get started securing your GraphQL endpoints, you can use the link below.
Disclaimer - I am the CEO of Aista, and you might want to ask your senior developer(s) if the above assessment of the security threats related to GraphQL, PostgREST, and Firebase is correct or not, before trusting my words. After all, both Hasura, Supabase, and Firebase are competitors of Aista ...
Just sayin' ...
Below is the code I am using in the video.
.arguments
email:string
.description:Intercepts our GraphQL endpoint
// Endpoint we're intercepting.
.endpoint:"https://my-app.hasura.app/graphql"
/*
* Lambda object executed as an "intercepted lambda object"
* before invocation to HTTP endpoint.
*/
.before
validators.mandatory:x:@.arguments/*/email
validators.email:x:@.arguments/*/email
/*
* This is where you would parametrise your above [.before] object
* with for instance arguments given by the client.
*/
// Evaluating [.before] lambda object.
eval:x:@.before
// Retrieving Hasura's JWT token from configuration settings
config.get:"hasura:jwt"
// Forwarding arguments given to endpoint to intercepted endpoint.
add:x:../*/http.post/*/payload
get-nodes:x:@.arguments/*
// Invoking the intercepted HTTP endpoint.
http.post:x:@.endpoint
headers
Content-Type:application/json
Authorization:x:@config.get
convert:true
payload
// Sanity checking invocation to endpoint.
if
not
and
mte:x:@http.post
.:int:200
lt:x:@http.post
.:int:400
.lambda
log.error:Something went wrong as we invoked our intercepted HTTP endpoint
endpoint:x:@.endpoint
status:x:@http.post
result:x:@http.post/*/content
throw:Intercepted endpoint did not return success
public:true
status:502
// Return result to caller.
add:x:+
get-nodes:x:@http.post/*/content/*
return
This content originally appeared on DEV Community 👩💻👨💻 and was authored by Thomas Hansen
Thomas Hansen | Sciencx (2022-10-07T13:16:55+00:00) Securing GraphQL. Retrieved from https://www.scien.cx/2022/10/07/securing-graphql/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.