I’ve been working further on my application, and run into a few challenges and issues with CSRF, so I’m elaborating a bit on my earlier post. At some point my tutorials will be updated to deal with this, but for now this is a place holder that describes what CSRF protection does, where the issues lie, and what resolutions I’ve found to the overall problem.
Firstly, it seems that there are two general developer classes with Rails – those who are developing a Rails web application and therefore use Rails to create the pages, and those who are building an API using Rails, and seem to turn off CSRF protection and use an API key to authenticate (in a sense I see an API key as a long-lived username and password, so I’m not a big fan for applications that require strong security).
I’m living in a middle space – the application front-end is all AngularJS, and it’s calling Rails asynchronously using JSON. But I’m still aiming to use Devise as my authentication engine, and I want to use CSRF to protect against malicious scripts that manipulate the API without the user knowing it. The default configurations don’t really appear to deal with this situation well.
In discussing the solution, I’ll start with a simplified discussion of what CSRF protection should and shouldn’t do, and then what pieces are needed to integrate (reasonably) cleanly.
This post adds internationalisation (i18n) to the app using the angular-translate library. This library allows “on-the-fly” translation of content, and permits dynamically changing languages with automatic page refresh.
I’m using the sample league app that was built in this series, building on the code base from github that existed at the end of tutorial 7. This commit also included the devise authentication from this post, or hit the tutorials menu at the top and select the Rails 3 tutorial.
In reading the AngularJS documentation for the $http service, there is a very clear warning about a potential JSON/JSONP vulnerability. The short version of this is that JSONP was introduced as a technique to build mashups and composite applications, it allows one domain to call services on another domain.
The outline description of this can be found on the AngularJS $http page, in the security considerations section.
The CSRF vulnerability mentioned on that page is dealt with in this post on this blog. This post provides my current solution to the JSON/JSONP issue.
It would be great if the rails generator could generate the angular views for us, this post walks through tailoring the generators to give that outcome. The format for the angular content I’m going to generate matches the setup in my various AngularJS and rails tutorials, and in particular the angular components created match those of the ng-boilerplate project.
We’ll assume that we want to create an angular view that offers a list and a modal form, with CRUD functionality and a unit test that hits the highlights. We’re not going to try to update the app.js file or index.html, that’ll have to be done manually. We’re going to follow the edgeguide on generators for guidance.
Having spent some time building a sample app that integrates rails with AngularJS, I’m now looking at some of the other features to make that functionality more enterprise-ready. The framework I’ve been working on uses devise, cancan and rolify to control access to applications.
In this configuration devise provides the authentication, and cancan/rolify provide role based access to functions within the application. I’ll deal with cancan and rolify in a later post, as it’s necessary for Angular to know what accesses you have in deciding what links and buttons to show you. In this post, we’ll deal with using Devise for logon with an AngularJS frontend.
This will break down into three main elements:
- Provision of a registration page that matches the Devise expectations and calls the Devise register method and password change method
- Provision of a logon page that matches the Devise expectations and that calls the Devise logon method and associated methods such as password resets etc
- Provision of functionality such that AngularJS can detect that a user is not logged on and redirect the user to the logon page, rather than just having each server interaction fail
In working through AngularJS and Rails integration, one of the matters that comes up frequently is CSRF protection. This is an important security measure, and this post points to the solution that I found on stackoverflow, and provides the code snippet that I implemented, and how I verified that it seems to be working. This content has also been included in the Rails 3 and AngularJS tutorial, available from the tutorials menu above, and the Rails 4 and AngularJS tutorial, also available from the tutorial menu above, or this specific post within that tutorial.
There is also a more thorough treatment of this content in another post, here (described in more detail at the bottom of this post).
Part 4.5 of a tutorial that connects AngularJS to a Rails backend. This post focuses on creating karma unit tests for the edit controller and the modal dialog, including mocking the modal dialog. The previous post was ngGrid and a modal popup, the next post is New and Delete. You can also find the index of the posts in the tutorial, or hit the tutorials menu at the top and select the Rails 3 tutorial.
I’ve split this content out into a separate post for two reasons. Firstly, at time of writing this is incomplete, I still have an outstanding item on verifying the parameters passed in as promises. Secondly, it’s going to be reasonably complicated once it’s done, and I’m assuming that some people will just want to get their Angular app going, and skip over the testing. So, a separate page.
There is a newer, rails 4 and newer angularJS, version of this tutorial. It is also more complete and has a nicer UI that doesn’t use modal windows, which is probably a better choice for anyone starting fresh today. The first page in that tutorial is here, and the index here.