Have You Tried Just Using a Function?

Written by Pete Corey on May 29, 2017.

Last month I read Sasa Juric’s To Spawn, or Not to Spawn article and its been lurking in my subconscious ever since.

I was recently working on the command handler and event sourcing system that drives my new project, Inject Detect, and this exact topic reared its head. I realized that I had been overcomplicating the project with exessive usage of Elixir processes.

Refactoring my command handler from a process into simple functions hugely simplified the application, and opened the doors for a new set of functionality I wanted to implement.

The Command Handler Process

For a high level overview, a “command” in Inject Detect represents something you want to do in the system, like requesting a new sign-in token for a user (RequestSignInToken), or ingesting a batch of queries from a user’s application (IngestQueries).

Commands are “handled” by passing them to the command handler:


%IngestQueries{application_id: application.id, queries: queries}
|> CommandHandler.handle(command)

The job of the command handler is to determine if the command is allowable based on the state of the system and the current user’s authorizations. If valid, the command being handled (IngestQueries in this case) will produce a list of events (such as IngestedQuery and IngestedUnexpectedQuery). These events are saved to the database, and a handful of “event listeners” are notified.

Command Handler as a Process

Originally, the CommandHandler was implemented as a GenServer-based Elixir process. The call to CommandHandler.handle triggered a GenServer.call to the CommandHandler process:


def handle(command, context \\ %{}) do
  GenServer.call(__MODULE__, {:handle, command, context})
end

The corresponding handle_call callback would handle the command, store the resulting events, and synchronously notify any interested listeners:


def handle_call({:handle, command, context}, _, []) do
  with {:ok, events, context} <- handle_command(command, context),
       {:ok, _}               <- store_events(events),
  do
    notify_listeners(events, context)
    {:reply, {:ok, context}, []}
  else
    error -> {:reply, error, []}
  end
end

Triggering Commands from Listeners

For several weeks, this solution worked just fine. It wasn’t until I started adding more complex event listeners that I ran into real issues.

I mentioned earlier that event listeners are notified whenever an event is produced by a command. In some cases, these listeners may want to fire off a new command. For instance, when an IngestedUnexpectedQuery event is fired, a listener may want to execute a SendUnexpectedEmail command.

Implementing this feature blew up in my face.

Because listeners are called synchronously from my CommandHandler.handle function, another call to CommandHandler.handle from within a listener would result in a GenServer timeout.

The first call to CommandHandler.handle  won’t reply until the second CommandHandler.handle  call is finished, but the second CommandHandler.handle call won’t be processed until the first call finishes. The second call will wait until it hits its timeout threshold and eventually fail.

We’ve hit a deadlock.

The only way to handle this situation would be to execute either the second call to CommandHandler.handle, or the entire listener function within an unsupervised, asynchronous process:


Task.start(fn -> 
  %SendUnexpectedEmail{...}
  |> CommandHandler.handle
end)

I wasn’t willing to go down this road due to testing difficulties and a general distrust of unsupervised children.

Command Handler as a Function

After mulling over my deadlock problem, the solution slapped me in the face.

The functionality of the command handler could be entirely implemented as a module of simple functions. No process or GenServer required.

A quick refactor led me to this solution:


def handle(command, context, listeners) do
  with {:ok, events, context} <- handle_command(command, context),
       {:ok, _}               <- store_events(events)
  do
    notify_listeners(events, context, listeners)
    {:ok, context}
  end
end

After the refactor, a synchronously called event listener can recursively call CommandHandler.handle to handle any follow-up commands it wants to execute.

Perfect.

Have You Tried Just Using a Function?

In hindsight, I had no particular reason for implementing the CommandHandler module as a GenServer. It managed no state and had no specific concurrency concerns that demanded the use of a process.

When given a hammer, everything starts to look like a nail.

Remember to use the right tool for the job. In many cases, the right tool is the simplest tool. Often, the simplest tool for the job is to just use a function.

NoSQL Injection in Kadira

Written by Pete Corey on May 22, 2017.

Not long ago, the Meteor Development Group purchased Kadira after the Kadira team announced it would be shutting down. Shortly after, MDG open sourced the entire project on Github. 🎉

Being the curious developer that I am, I decided to sleuth through Kadira’s source looking for trouble.

I found several security issues which I reported to Meteor’s security team and were promptly fixed. Of those issues, the most notable was a NoSQL Injection vulnerability in Kadira’s user-facing kadira-ui Meteor application.

Let’s dive into the vulnerability and take a look at why it exists, how it could have been exploited, and how to prevent it.

Finding the Vulnerability

The best way to hit the ground running when looking for NoSQL Injection vulnerabilities in a Meteor application is to grep for calls to Meteor.methods, or Meteor.publish. This gives you a very quick idea of the entry points available to you as a user (or an attacker).

After finding all methods and publications, your next step is to peruse through every argument being passed into each method and publication and make sure that they’re being thoroughly checked.

In the kadira-ui project, I managed to find a Meteor method that wasn’t thoroughly checking its arguments. The "alerts.create" method was checking that the alertInfo argument matched Match.Any. Unfortunately, checking that an argument matches Match.Any is roughly equivalent to not checking it at all.

This is looking promising.

Tracing out the path of this method showed that alertInfo is passed into a function called setAppName. An appId field is pulled out of the alertInfo object and is ultimately passed directly into a MongoDB query:


var appId = alertsInfo.meta.appId;
var app = Apps.findOne(appId);

Passing an unchecked argument into a MongoDB query is the perfect recipe for a NoSQL Injection vulnerability.

Exploiting the Vulnerability

Because we, as intrepid explorers/malicious attackers, have complete control over the data passed into the Apps.findOne query, we’re presented with a few different choices in how we could exploit this vulnerability.

We could try to target a random application in the database by passing in a special MongoDB query operator when calling "alerts.create" from the client, like {_id: {$gte: ""}}:


Meteor.call("alerts.create", { meta: { appId: { _id: {$gte: ""} } } });

Or we could try something more impactful.

Because we have control over the entire query, we can pass in a $where query operator. The $where query operator is special in that it lets us pass in and execute raw Javascript in the MongoDB database process.

We can use this to our advantage to initiate a Denial of Service attack against the database and the Meteor application itself:


Meteor.call("alerts.create", {
    meta:{
        appId:{
            $where: "d = new Date; do {c = new Date;} while (c - d < 100000);"
        }
    }
});

In this example, we’re providing a query that will run a tight, unyielding loop for one hundred seconds per document in the Apps collection. It’s important to realize that this one hundred second time limit can be extended indefinitely or removed altogether.

We’ve essentially thrown the database into an infinite loop.

Pegging the CPU of the MongoDB host in this way drastically reduces the availability of the database and in many situations renders the Meteor application completely unusable.

With a single query, we’ve taken down the entire application.

Read more about the dangers of the $where query, and watch me exploit a similar vulnerability in my “NoSQL Injection in Modern Web Applications” talk given at CraterConf!

Fixing the Vulnerability

The fix for this specific instance of NoSQL Injection is to more thoroughly check the alertsInfo argument passed into the "alerts.create" method.

We’re expecting appId to be a String, so let’s check that it is:


check(alertInfo, Match.ObjectIncluding({
    meta: Match.ObjectIncluding({
        appId: String
    })
}));

If a malicious user provides anything other than a String (like a {$where: ...} query operator) in the appId field, our method will throw an exception.

Ideally, it would be better to fully flesh out the expected schema of alertInfo and avoid using Match.ObjectIncluding, but I’m not familiar enough with the application to make that change. In your application, you should check every field of every argument down to its primitive fields.

This change is enough to prevent a NoSQL Injection attack through the alertInfo.meta.appId field.

Even though Meteor isn’t actively maintaining their open sourced version of Kadira, I submitted a pull request to the project for posterity and to warn future users of the vulnerability.

Thanks to the Meteor Team

I’d like to give a huge shout out to the Meteor team for their speedy and professional response to this situation.

Nick Martin responded to my report within ten minutes and confirmed and patched my findings in their internal version of Kadira within twenty four hours.

Not only that, but they sent me a killer collection of swag!

I’d also like to thank MDG for swooping in during a time of crisis within the community, purchasing the Kadira platform, and open sourcing the entire product to the world. That act should be seen as no small gift to the Meteor community.

Inject Detect

If you’ve been following along for the past few months, you’ll know that I’m deep into the development of my security-focused project, Inject Detect.

Inject Detect is being developed to fight the exact problem I laid out in this article: NoSQL Injection. NoSQL Injection is an incredibly prevalent vulnerability in Meteor applications, and I’ve been fighting a war against it for years now.

Inject Detect is my newest and most powerful weapon to combat the threat of NoSQL Injection.

While Inject Detect is still under development, I’m fast approaching a releasable version. Be sure to sign up for the Inject Detect newsletter to stay up to date on its upcoming release!

GraphQL Authentication with Apollo and React

Written by Pete Corey on May 15, 2017.

Continuing on from last week, we have our authentication and authorization workflow ironed out in our Elixir/Absinthe powered back-end. Fantastic!

But what about the front-end?

How do we get our auth_token (or authToken, once it’s passed through Apollo) from the server? How do we manage active user sessions on the client? How do we ensure our authToken is passed up with each request? How do we handle authentication failures?

More great questions! Let’s dive in and set up client-side authentication in our React/Apollo-powered front-end.

Getting Our Authentication Token

In order to have an authToken to authenticate our GraphQL requests, we first need to get one from the server.

An authToken can be returned by any publicly accessible GraphQL mutation, such as a signIn mutation, or in my case, a verifyRequestedToken mutation.

Assuming we’re in an Apollo-wrapped React component with a mutation function called verifyRequestedToken, we can call it to retrieve our authToken:


this.props.verifyRequestedToken(token)
    .then(({ data: { verifyRequestedToken: { authToken } } }) => {
        localStorage.setItem("authToken", authToken);
    })

Once we retrieve the token from the verifyRequestedToken mutation, we’ll store it in localStorage for later use.

Attaching Our Authentication Token

Now that we have our hands on an authToken, we can send it up with each GraphQL request made from the client.

But how do we do this?

Apollo middleware gives us an easily accessible hook into all requests made against our GraphQL server. Let’s add a middleware function to our network interface that attaches our token:


networkInterface.use([{
    applyMiddleware(req, next) {
        let authToken = localStorage.getItem("authToken");
        if (authToken) {
            req.options.headers = _.extend(req.options.headers, {
                authorization: `Bearer ${authToken}`
            });
        }
        next();
    }
}]);

This middleware function checks to see if an authToken is stored in localStorage. If it is, it’s added as a bearer token to the authorization header of our GraphQL request.

Otherwise, if no authToken is found in localStorage, no authorization header is set.

Remember, if no authorization header is provided, our Absinthe server will let the unauthorized user access publicly available mutations and queries. An invalid authToken will result in an authorization error at the HTTP level.

Handling HTTP Authentication Errors

If an invalid authCode is passed up to the server, the server will return a 403 authorization error. This error is returned at the HTTP level, not as a GraphQL error.

We can add another layer of middleware, or “afterware”, to our network interface in order to catch these 403 errors as they come back from the server:


networkInterface.useAfter([{
    applyAfterware({ response }, next) {
        if (response.status === 403) {
            localStorage.removeItem("authToken");
        }
        next();
    }
}]);

In the afterware function, we check each response for a 403 status. If we encounter a 403 response, we clear the current authToken from localStorage, effectively signing out the current user.

When using Apollo in this way, clearing the authToken from localStorage signs the user our for subsequent requests, but the currently signed in user object is still floating around in the client’s data store.

In Inject Detect, I’m flushing this user out of the client’s data store by manually querying for the current user (user) after removing authToken from localStorage:


client.query({
    query: gql`
        query {
            user {
                id
            }
        }
    `,
     fetchPolicy: "network-only"
});

Specifying a fetchPolicy of "network-only" forces the Apollo client to fetch the current user from the server, rather than returning the user cached on the client.

Because this query is made without an authToken, no user is returned from the server. The user in the client’s store is cleared out, and any components relying on this query result are re-rendered.

Full disclosure - there are probably better ways to update the store in this situation. If you have any suggestions, or are doing something similar, please let me know!

Handling GraphQL Authentication Errors

You may remember that on top of throwing HTTP authentication errors, our GraphQL resolvers will also throw authorization errors if the current user doesn’t have permission to access a given query or mutation.

These errors will be handled inline, at the source of the query or mutation, just like any other GraphQL error.

Let’s run through an example.

Going off of our examples from last week, let’s pretend that we’re accidentally showing the “Sign out” button to unauthenticated users. Clicking the sign out button triggers a signOut mutation:


this.props.signOut()
    .then(() => localStorage.removeItem("jwt"))
    ...

If we try to call this mutation as an unauthenticated user, the sign_out resolver will throw a GraphQL error down to the client. We’ll need to catch this, parse the resulting graphQLErrors, and show the errors to the user in some meaningful way:


this.props.signOut()
    .then(() => localStorage.removeItem("jwt"))
    ...
    .catch((err) => {
        let errors = _.isEmpty(err.graphQLErrors)
                   ? ["Unexpected error."]
                   : _.map(err.graphQLErrors, "message");
        this.setState({ errors });
    });

Any resulting errors can be rendered by the component in a way that makes sense in the context of the application.

Final Thoughts

With that’s we’ve set up a full-stack authentication system using React, Apollo, Absinthe, and Elixir!

While all of the moving pieces can feel daunting at first glance, breaking the problem into its piece components leads us to a relatively simple solution. All we needed to build a basic Apollo-powered session management system on the client was two middleware functions and some basic error handling.

Not bad for a day’s work.