Create a generic template for JSON from rails application

I am writing a rails application with the AngularJS interface, it is part of the tutorial series that I am writing on connecting rails and corner symbols . This means that the rails application communicates with the browser exclusively in JSON.

In angularjs $ http documentation, it describes the potential json security vulnerability when a json request can be embedded in a script tag, plus some tricky use of jsonp to allow something akin to a cross-site scripting attack. I found several other pages, in particular, I thought I described it well and dates from 2008, so this is not a new problem.

Apparently, this is not a vulnerability in the standard rails json rendering, since by default the rails return an object containing an array. But when working with angularjs, we seem to set root: false (although I have to admit that I cannot find where I did this, but it definitely does not give the root root).

In any case, the bottom line is that the angular documentation recommends prefixing any json response with c)]} ', therefore:

['one','two'] 

becomes

 )]}', ['one','two'] 

Angular will then automatically disable this again.

I am looking for a way to do this elegantly. I saw a lot of questions and answers on stackoverflow about this, but most of them were either related to much earlier versions of the rails before the JSON processing was more thoroughly built-in or seemed to require me to create a large code template. I am looking for a method that I can apply to an application controller or as a helper method that will work everywhere.

The controller that I am currently using is as follows:

 class ClubsController < ApplicationController respond_to :json # GET /clubs.json def index @clubs = Club.all render json: @clubs end end 

This does not cause any templates - the rendering action skips the template engine. I can make this work by changing the visualization bar so that:

 respond_with json: @clubs 

And creating template / club / index.json.erb files containing

 )]}', <%= raw(@clubs.to_json) %> 

But I would have to create a template for each action on each controller, which would look like a template. Instead, I would like to be able to modify views / layouts / application.json.erb to have something like:

 )]}', <%= yield %> 

But this does not work, because we only get templates when calling response_with. And if we call response_with, we will not be able to put @clubs in the answer - so in the end we get:

 )]}', 

As a complete answer.

An alternative, perhaps, would be to override the as_json method to add what I want, but it looks like a sledgehammer. Ideally, there would be a place where I could introduce a helper method, for example:

 render prepend_vulnerability_protection(json: @clubs) 

So, after all this, two questions:

  • This is even a real problem, or Rails already has some other protection, which means I don’t have to worry about it at all.
  • Is there a way to do this centrally, or do I need to bite a bullet and create all the template templates? I can modify scaffold generators to do this, so this is not the end of the world, but it looks like a lot of patterns.
+4
source share
1 answer

So, there are no answers yet. I am going to write down what I found from my research, and my current answer.

Firstly, I think this is a real vulnerability in rails. Unfortunately, rails and JSON / JSONP had some other recent vulnerabilities related to the JSON parser at the end of Rails. It really drowned out any Google search related to this particular XSS issue.

There are several approaches to solving this issue:

  • Ask your application to respond only to put / post / delete requests. This is not exactly an option when integrating with Angular - well, that does mean, but that means overriding a bunch of standard behavior.
  • Insert something at the beginning of the returned JSON - it could be the root node (the default behavior on rails in rails 3, no longer in 3.1), closing like)]} ;, or a loop like while (1) ;. Angular expects and can deal)]} ',

I examined the use of the json template in my rails application. You can do this with one of the many gems that I like the look of JBuilder ( railscast 320 ), but RABL, perhaps more powerful ( railscast 322 ).

This means a template for each of the actions on each of the controllers. However, I also just finished work on how the rails automatically fixed them for me , so it’s not as scary as it was when I first asked a question, and I see some other reasons that I might need more control over json that is returning from my application.

Having said that, I could not immediately see a way to force JBuilder to add an arbitrary string - it seems that it only wants to prepare a valid JSON (and I consider this to be invalid JSON). RABL looks like it can do it, but it's a little trickier. This can be done simply by using ERB, but I feel bad about it.

Another alternative that I have identified is a helper method in application_controller.rb, which I then call in each of my controller methods. It is elegant enough and I can easily modify my template to do this. So I'm going to do it now:

 class ApplicationController < ActionController::Base def render_with_protection(json_content, parameters = {}) render parameters.merge(content_type: 'application/json', text: ")]}',\n" + json_content) end end class ClubsController < ApplicationController respond_to :json # GET /clubs.json def index @clubs = Club.all render_with_protection @clubs.to_json end # GET /clubs/1.json def show @club = Club.find(params[:id]) render_with_protection @club.to_json end # POST /clubs.json def create @club = Club.new(params[:club]) if @club.save render_with_protection @club.to_json, {status: :created, location: @club} else render_with_protection @club.errors.to_json, {status: :unprocessable_entity} end end end 

Please note that you must also enable CSRF protection in your application controller, so see this as an addition to the security precautions that you have already taken, and not a replacement.

+4
source

All Articles