Filter Rails JSON input with route constraints

Following the recent YAML parsing vulnerabilities in Rails, I decided to act on an idea I had a few months ago: using route constraints to define strict API contracts in Rails.

Sadly, it does not protect against the YAML parsing problem (and the probable similar vulnerabilities we will see in the following months), because the request is interpreted before going through the route constraints. But it can protect from the mass assignment vulnerability., and probably some SQL injections.

Here is the idea: Rails 3 introduced the route constraints, a way to execute fonctions on the request before it is passed to the controllers. By combining it with the json-schema gem, we can filter the JSON input quite easily.

For the following example data:

{"echo" : "blah", "nb" : 1, "data": [1, 2, 3]}

We can define the following schema:

{
    "type": "object",
    "$schema": "http://json-schema.org/draft-03/schema",
    "id": "#",
    "required": false,
    "additionalProperties": false,
    "properties": {
        "data": {
            "type": "array",
            "id": "data",
            "required": false,
            "items": {
                "type": "number",
                "id": "0",
                "required": false
            }
        },
        "echo": {
            "type": "string",
            "id": "echo",
            "required": false
        },
        "nb": {
            "type": "number",
            "id": "nb",
            "required": false
        }
    }
}

(Use the JSON schema generator to create your own)

Save this schema to “data.schema” and add “json-schema” to your Gemfile. You will then be able to filter inputs with code like the following “config/routes.rb”:

require "json-schema"
class LolJSONConstraint
  def matches?(request)
    if(request.headers["CONTENT_TYPE"] == "application/json")
      JSON::Validator.validate("data.schema", request.headers["action_dispatch.request.request_parameters"])
    end
  end
end

Yamlvuln::Application.routes.draw do
  resources :posts, :constraints => LolJSONConstraint.new
end

The constraint will load the schema, and apply it to the incoming data, and return a 404 error if the JSON is invalid. The “additionalProperties” set to false in the schema is required to refuse the properties you didn’t define and protect the application from mass assignment.

If I tried, for example, to send the following JSON to the application, there would be an error:

{"echo" : "blah", "nb" : "UNION ALL SELECT LOAD_FILE(CHAR(34,47,101,116,99,47,112,97,115,115,119,100,34))", "data": [1, 2, 3]}

As I said before, it is not safe against the YAML parsing vulnerability. Also, I did not really test the performance of this. But it is still a nice and easy solution for API filtering.

Advertisements

2 thoughts on “Filter Rails JSON input with route constraints

  1. It’s a bad idea. If the submitted JSON is invalid you should return a 422 (Unprocessable Entity), or at least a 400 (Bad Request) but definitely not a 404 (Resource Not Found).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s