Graphql - Phoenix - APIs and security

Hello!

This is technical question, actually I’m working with phoenix and absinthe for my web app, but I have some question about Grahql and the security of it…

I already read some post on internet about how to “secure” your Graphql api etc… But basically all people tells that you need first authenticate the user and after recieve the data, but lets suppose a website like here ElixirForum…

All post/members are avaliable to non logged users and you can navegate the forum without any problem… Now lets suposse someone create a bot to make a lot of api request, it will be blocked (I suppose), well thats exactly what I’m looking for… How to secure api against abuse from externa users on an authenticate and non authenticate way with Phoenix? Do I need add a captcha after many request? How you know exactly than a user its making many request? Also more patterns to secure a API if its possible…

My phoenix app don’t server any html, its completely for API and Channels (waiting for subscription on absinthe) use, so I want if someone can give me recommendations to secure it :smiley:

I’m sorry if my English is not good I still learning ^^’

There’s probably a few different ways to handle it in the latest version, but one I saw @benwilson512 mention in the slack channel that struck me as elegant is to have a function that returns a function which acts as a security gate on your resolver, something like this:

#schema 
field :my_object, :object_type do
  resolve must_be_admin(&Resolvers.resolve_my_object/3)
end

#outside of schema, assumes you've added the current user to the context based on auth mechanism
def must_be_admin(resolver) do
  fn 
     parent, params, %{context: %{current_user: %{admin: true}}}=res -> resolver.(parent, params, res) 
     _, _, _ -> {:error, :not_an_admin}
  end
end

I’ve probably butchered what was said, but that’s the gist of it… You can probably find a more elegant way of doing this with middleware now as well, since that’s been added in 1.3.

Yeah with the introduction of middleware this pattern is not really what you want to do.

Before we get to that though, I want to understand the problem a bit better.

If you allow unauthenticated API requests then it will not be blocked. I don’t know of any way for an API to tell the difference between a human being and a “bot”. For one thing most APIs actually get hit from other programs, like the javascript running in a browser.

If you want to know more about how to do authentication with GraphQL you can check our guides http://absinthe-graphql.org/guides/ , which we will expand on this week to include more middleware content. For now you can check the middleware docs: Absinthe.Middleware — absinthe v1.7.6

Trying to block bots isn’t a GraphQL responsibility, nor is it something that I think makes sense for APIs. If you need to do rate limiting to make sure a client doesn’t make too many requests you can look into that, but that isn’t a GraphQL responsibility either.

I would say this is more responsibility of the transport (HTTP) layer, than the application itself (with GraphQL).

Some time ago I extracted (and generalised) this functionality from hexpm in the form of plug_attack package.

The simplest way is to e.g. throttle requests to 10/min/IP or something similar.

3 Likes

First of all @karmajunkie @benwilson512 thanks to answer! ^^

I think my biggest problem is communicating correctly in English (sorry about it), I already know things like authenticate and middleware etc…

Sure, I know it, in general my real question maybe is How to secure a api against abuse use?

What I was triying to say with Graphql it’s an example, how and authenticate user can abuse like a non autenticate user so how avoid this kind of things at the HTTP layer of Phoenix (I know that is not a work from graphql itself)

So many thanks, a answer like this its exactly what I’m searching for, like I’d say on my previous comment, I have some problems to express exactly what I need (or the main idea) when I write on english, sorry about it.

I’ll take a look to the library, again thanks! ^^

I think your English is great—I just didn’t read your original question all the way through! :-/ Sorry for clouding up the discussion…

Definitely what @michalmuskala said. I’ve not written any throttlers on my current system (its internal anyway), but I have in the past, this is absolutely how this should be handled. Instead of just a number of requests per minute I’ve in the past made it with a certain ‘weight’ per IP/user per minute/hour and for simple queries they may have a weight of 1 or 5 and complex ones like something that returns a large list may have a weight of 500 or something, and once exceeded then just return the normal HTTP error code of too fast or whatever it was called.

1 Like