GraphQL gives away to much info and this hurts it's security

It just doesn’t accept any file upload at all until that point. There is no upload, full stop, on a non-authenticated socket. The client gets a redirect HTTP response at best, or at worst the LiveView crashes and they go back to the start.

There simply isn’t anything to abuse until they are authenticated and authorized for uploads (different user accounts have different privileges on different objects)

But isn’t that early refusal to accept files achievable with nginx (or any good load balancer / reverse proxy) + Phoenix as well? Maybe I am not following well.

This is not a popular opinion and I don’t feel like explaining why I need/support this (because I’ve had to do it in the past and bleh). But I agree completely and things like this do bother me about GQL usage for private APIs.

Here’s middleware that will disable introspection, at least as far as I’m aware.

defmodule GraphqlService.Schema.IntrospectBlocker do
  @behaviour Absinthe.Middleware

  def call(resolution, _config) do
    case Absinthe.Resolution.path(resolution) do
      ["__schema" | _] ->
        %{resolution | errors: ["__schema introspection is disabled"]}

      ["__type" | _] ->
        %{resolution | errors: ["__type introspection is disabled"]}

      _ ->
        resolution
    end
  end
end
2 Likes

Yes, if it is implemented properly for each and every endpoint. And the more complex the rules for that endpoint become, the more likely it is for a silly human being like me to get it wrong. :wink: It also relies on all the bits of software being able to do exactly what the app developer has in mind … when the configurability of those components no longer is sufficient, then what?

This is complicated by details like default endpoint configuration being application-level in most of these cases, rather than per-authenticated-connection. Example: “this endpoint will accept files up to N bytes in size” (e.g. the length parameter handed to Plug.Parsers) … and we’ll sort the real constraints out during authentication (which is necessarily code that is run after configuration values are applied).

That is backwards: the endpoint should never accept anything at all, full stop, until authorization has had a chance to do its thing. I ended up having to place part of the authorization in the Multipart uploader, entirely separate from the file processing function in the Controller (which also had to do its own checks), and even that only got run after the file made it through the actual webserver upload.

So, yes, it is possible to achieve something similar … but in practice it is more code, spread out over more places, is not always possible to perform the full authorization path desired at every relevant stage, and is all done via a publicly-exposed endpoint.

I used to have conversations with C programmers who insisted it was possible to write complex C programs securely. They were, of course, right. It absolutely is possible, at least theoretically. But unless your name is D. J. Bernstein, it’s entirely unlikely, and the history of servers and OS’s written in C have shown that to be the case.

Design principles such as “don’t expose API until authorized”, “don’t spread authorization across disconnected components”, “multi-stage authorization is always harder”, “a single source of truth is easier to get right”, “unit tests are easier and more reliable than integration tests”, etc. exist to make it more likely to get it right … or at least more likely to not get it wrong.

C programs were plagued by the same set of security issues for literally decades until a combination of tools improving, enough time passing to find most of the worst bugs and fix them, and people not using C for those sorts of use cases to avoid the pitfalls has started to reduce the constant threat of buffer overflows and the like.

The web is going through something similar. LiveView is not a silver bullet. It has its own complexities, and there is still room for me to shoot my feet off. But it is far easier to get right, and that is mostly because it keeps all the right pieces together in the place they belong and can be most easily tested.

2 Likes

That’s basically the crux of the turf war between C/C++ programmers and Rust programmers. :003: And I completely agree with you.

Thanks for the clarifications, I see what you mean: you get protection with little effort (and upfront), as opposed to having to plug every hole reactively. That’s a clear win indeed.

2 Likes

I agree that obscurity can add another layer of security. In some cases I’ve seen that this layer was seen as too important and the main security layer was more of an afterthought.

So I would rather have people be serious to implement the main security layer than believing that hiding the API will be safe enough.

But none of this is an excuse to have APIs leaking too much information just for the sake of developer convenience during development or just to make it easier on client code.

Attackers know very well how to exploit this well known weaknesses from developers and when you see a proof of concept for an exploit in CVE it has more often then not a chain on weaknesses being exploited.

2 Likes

The headline part of the article here is what I addressed:

The article even arrives at the same conclusion about the real vulnerability:

It isn’t about introspection, it’s about parameter validation.

I also addressed general questions about whether or not GraphQL makes it easier to understand what APIs exist. The thing your repeated posts about the insecurity of discoverable APIs miss is that anyone with a browser and a network tab can read API calls. I realize that GraphQL’s introspection or “did you mean” features can allow folks to find attributes that aren’t currently used on the page, but the exploit in question didn’t really rely on that.

However all of this is a bit moot: Absinthe supports pre-validated documents which prevents any unknown documents from working at all. If you want to have an API that feels entirely closed, but still allows for easy iteration in development, use that.

This is “begging the question” in the debate sense of the phrase. The issue at hand is precisely whether API shape is “too much information”.

I agree that defense in depth is critical. I disagree that hidden API shape is part of that depth. As for the larger discussion WRT pros / cons of GraphQL I’m gonna stay out of that for now and focus on this security question.

Now I unserstand your confusion, and as I said you have not read my topic with attention:

To be crystal clear the newsletter has more then 1 article, and you need to read the one about clairvoyance tool, that is the last one.

So, you have addressed the wrong article in your replies :wink:

Read the last article in the newsletter about the tool clairvoyance. Once more it’s not about the Facebook article.

And just because you can hit F12 in the browser or do a MitM attack on the web or mobile app, that is still not an excuse to have an API leaking more info then it should. This is a well understood problem by security researches, but not well understood by developers :wink:

As I recommend to others already, I also recommend to you to do the Hack Yourself First course, because it’s an eye opener, and please don’t be offended with me for recommend this course to you, because I do it a lot in my professional life to developers of any level of seniority, even to the ones with more then 30 years of experience.

As a minor FYI, the regular use of :wink: is communicating a patronizing demeanor that is significantly detracting from the enjoyability of this conversation.

an API leaking more info then it should.

You continue to state, but not actually argue for, that the shape of an API is “more data than it should”. “too much” is by definition bad, to facetiously quote Fry and Laurie: “Too much is precisely the quantity that is excessive”. If you are AWS S3, the API shape and documentation is not too much or excessive, it is in fact the service.

In any case, I would like to draw your attention to my comments about Absinthe’s pre-validated documents. If you wish to have a GraphQL API, and you wish to disable people querying against it arbitrarily, pre-validated docs are the way to go.

If the point of the GraphQL API however is to be public and usable by end customers / clients / etc then this whole point is moot.

4 Likes

I was not aware that using that symbol meant what you said now, thus my apologies, because I was not wanting to look smarter then you or anyone else here.

My intention when using it was the opposite… I was trying to not look aggressive or superior in my sentences.

3 Likes

@benwilson512 Is this described in the documentation? I’m having trouble finding it.

https://hexdocs.pm/absinthe_plug/Absinthe.Plug.DocumentProvider.Compiled.html

1 Like