Gqlgen: Query caching and whitelisting

Created on 23 Feb 2018  Â·  12Comments  Â·  Source: 99designs/gqlgen

hashing incoming queries and caching the document would improve parse times for large queries.

It would also serve as a great point to whitelist allowed queries.

Open question: how should the whitelist be specified?

Perhaps Persisted Queries?

question thinking

Most helpful comment

Hashing / caching would be pretty straight forward to implement, but would need to be measured before it lands. I wonder if there are any good graphql benchmark suites out there?

I think persisted queries offer a few big benefits:

  • locking down a graph to have a similar exposure footprint as REST.
  • protecting against malicious users: maybe something like https://github.com/ivome/graphql-query-complexity is probably better suited for public apis.
  • deleting deprecated fields: in a microservice environment knowing who is using what parts of the graph lets you fail in CI if you remove something thats still in use.

All 12 comments

I would be interested to see how hashing/caching the queries would work.

However, whitelisting queries (persisted queries) defeats the purpose of using GraphQL. On paper it seems like a great idea but it takes away the flexibility of GraphQL.

Hashing / caching would be pretty straight forward to implement, but would need to be measured before it lands. I wonder if there are any good graphql benchmark suites out there?

I think persisted queries offer a few big benefits:

  • locking down a graph to have a similar exposure footprint as REST.
  • protecting against malicious users: maybe something like https://github.com/ivome/graphql-query-complexity is probably better suited for public apis.
  • deleting deprecated fields: in a microservice environment knowing who is using what parts of the graph lets you fail in CI if you remove something thats still in use.

Adding complexity somehow to the context object in the resolver would be very nice! We were thinking of implementing some kind of ACL layer that rate limits complexity per user...

I imagine this would tie in to https://github.com/vektah/gqlgen/issues/5 which gives us access to the query in the resolver?

@vektah

locking down a graph to have a similar exposure footprint as REST.

If it was me, I would use REST instead. Why use GraphQL if I want to make it behave like REST? Not to mention, you can only add queries (cannot change or delete). So any change to an existing query requires updating the clients. This adds lots of maintenance in a microservices environment and if you have multiple user facing clients then REST style API versioning will come into play.

protecting against malicious users: maybe something like https://github.com/ivome/graphql-query-complexity is probably better suited for public apis.

In my humble opinion, this is definitely a much better option. You can truly secure your API but also keep benefiting from GraphQL flexibility.

deleting deprecated fields: in a microservice environment knowing who is using what parts of the graph lets you fail in CI if you remove something thats still in use.

I think this is a point against persisted GraphQL queries (PGQ)

Lastly, I am not totally against PGQ and I know it has some benefits but I think other options (i.e., depth limit, complexity/cost analysis) are better practices to secure GraphQL API.

Happy coding! 😄

Would it not be better to do any security / roles based security further
down. For instance at the grpc layer just above the db layer ?

On Sat, Mar 3, 2018, 4:22 PM Salman Ahmad notifications@github.com wrote:

@vektah https://github.com/vektah

locking down a graph to have a similar exposure footprint as REST.

If it was me, I would use REST instead. Why use GraphQL if I want to make
it behave like REST? Not to mention, you can only add queries (cannot
change or delete). So any change to an existing query requires updating the
clients. This adds lots of maintenance in a microservices environment and
if you have multiple user facing clients then REST style API versioning
will come into play.

protecting against malicious users: maybe something like
https://github.com/ivome/graphql-query-complexity is probably better
suited for public apis.

In my humble opinion, this is definitely a much better option. You can
truly secure your API but also keep benefiting from GraphQL flexibility.

deleting deprecated fields: in a microservice environment knowing who is
using what parts of the graph lets you fail in CI if you remove something
thats still in use.

I think this is a point against persisted GraphQL queries (PGQ)

Lastly, I am not totally against PGQ and I know it has some benefits but I
think other options (i.e., depth limit, complexity/cost analysis) are
better practices to secure GraphQL API.

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/vektah/gqlgen/issues/22#issuecomment-370155232, or mute
the thread
https://github.com/notifications/unsubscribe-auth/ATuCwt50vrGWPsDF2GDi1dIRdDv27sO5ks5tarVDgaJpZM4SQNHU
.

@gedw99

That's authentication/authorization and it does not prevent an authorized user to make N+1 & infinite circular relationship type of query request

@salmana1 But for security dont yo want 2 things:

  1. Before a query is made to know what the user can and cant do. Hence you can restrict the Nav and also restrict the queries they could type in a query IDE.
  2. After they make a query, and it hits the server, check each table they are hitting

I guess you knwo this but lots of projects use casbin to do policy based restrictions. Its very popular, and one of the useful aspects is that its runtime based, which is what you want because you want to apply the security in terms of what a roles can access at runtime.
https://github.com/casbin/casbin

If there is something i am missing in the big picture let me know...

first, i think cache is a field level or object level feature. its looks like

type Object @cache(10s) {
   id : Int @cache(10s)
   name: String @cache(20s)
   price: @cache(Never)
}

in the blow case, we can define a obejct level cache time and field level cache time.

Thats a different kind of caching. This issue is for the incoming query objects, not the resolver results

I've broken this out on the project board.

Were persisted queries implemented?
If so it'd be great to have the featured listed in the readme :)

Nope, just caching. Would be pretty easy to add the hooks required to lookup a query by ID and let the user implement the store

Was this page helpful?
0 / 5 - 0 ratings