← Back to Upcase

Humon App CSRF Warn on POST


(Jourdan Clish) #1

Greetings! Old C/Kernel dude here with 2 questions. 1) Using the example app from github for the IOS/Rails app (Humon) I have gotten the rails app working on heroku and on my iPhone and iPhone simulator. GET requests work but that very first user POST request fails. Log extract below:

2014-09-13T20:54:14.899204+00:00 heroku[router]: at=info method=POST path="/v1/events" host=damp-everglades-3991.herokuapp.com request_id=7dcb3230-1c0a-4ab9-996b-3b6f2d437f28 fwd=“99.103.199.15” dyno=web.1 connect=3ms service=142ms status=401 bytes=741
2014-09-13T20:54:14.759117+00:00 app[web.1]: Started POST “/v1/events” for 99.103.199.15 at 2014-09-13 20:54:14 +0000
2014-09-13T20:54:14.854710+00:00 app[web.1]: Rendered text template (0.1ms)
2014-09-13T20:54:14.833027+00:00 app[web.1]: Processing by Api::V1::EventsController#create as JSON
2014-09-13T20:54:14.833065+00:00 app[web.1]: Parameters: {“name”=>"Ysss ", “lat”=>37.78673118018515, “started_at”=>“2014-09-13T20:53:09.000Z”, “lon”=>-122.406417, “address”=>“120 Stockton St”, “owner”=>{“device_token”=>“B10DA8F7-E1AB-4F23-AF73-A75DE8AA7DE7”}, “event”=>{“name”=>"Ysss ", “started_at”=>“2014-09-13T20:53:09.000Z”, “address”=>“120 Stockton St”, “lat”=>37.78673118018515, “lon”=>-122.406417}}
2014-09-13T20:54:14.852696+00:00 app[web.1]: Can’t verify CSRF token authenticity
2014-09-13T20:54:14.855290+00:00 app[web.1]: Completed 401 Unauthorized in 22ms (Views: 1.7ms | ActiveRecord: 8.7ms)

I know I need to be capturing and sending back in the header something but I have not worked out how yet.

  1. Even though the rails app works on the laptop and heroku none of the tests work. This is a bummer 'cause I want to learn to be a TDD person. Here is a random example. Research says test db not set up right but there is no test:prepare. Any of the tests in the spec directory will fail right out of the box.

jourdanlap:rails jclish$ bundle exec rspec spec/
F

Failures:

  1. factory attendance is valid
    Failure/Error: factory = build(factory_name)
    ActiveRecord::StatementInvalid:
    PG::UndefinedTable: ERROR: relation “attendances” does not exist
    LINE 5: WHERE a.attrelid = ‘“attendances”’::regclass
    ^
    : SELECT a.attname, format_type(a.atttypid, a.atttypmod),
    pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
    FROM pg_attribute a LEFT JOIN pg_attrdef d
    ON a.attrelid = d.adrelid AND a.attnum = d.adnum
    WHERE a.attrelid = ‘“attendances”’::regclass
    AND a.attnum > 0 AND NOT a.attisdropped
    ORDER BY a.attnum

    ./spec/models/factories_spec.rb:6:in `block (3 levels) in <top (required)>’

Finished in 0.25799 seconds
1 example, 1 failure

Failed examples:

rspec ./spec/models/factories_spec.rb:5 # factory attendance is valid

Randomized with seed 53857

Many thanks for any input you have.


(Nailson Martins) #2

I’m working on a power quality web logger (using arduinos, by now) and you can disable csrf authentication. and i think that’s insecure (maybe i’m wrong).

here is my ApplicationController, it’s Rails 3.2, for Rails 4.x you just need to change:

skip_before_filter

to

skip_before_action


(Jourdan Clish) #3

Many thanks, sir. You just gave me a good clue! This is insecure as you note, but confirms my next course of action: I think I need to 1) Hit the API with a browser 2) See what the X-Header name of the token is 3) Modify the iOS code to a) make a GET at startup to “seed” the mobile app with the session token by pulling the server sent token from the header response and including it with all POST requests. Then I have to either force a load balancer to keep me on one host for the lifetime of a session, or figure out how to restore statelessness to a world where we imposed state by session!


(Nailson Martins) #4

@jclish session management is one of the things i need to learn, but in fact your idea is interesting. here’s the JSON request i’m making to the Rails app:

POST /powerlogs.json HTTP/1.1
Host: localhost:3000
Content-Type: application/json
Cache-Control: no-cache

{ “powerlog”: { “voltage”: 220, “current”: 1 } }

In fact i’ll go deep in this subject, because i can’t afford the risk to expose electrical equipment to web without the needed security.


(Jourdan Clish) #5

@nailson, let us go deep together then. By Google, others have written on this very topic. Here is the summary of the day’s research: 1) Be darn sure to understand the difference between “authentication” and “authorization”. 2) Regardless of the backend framework, do not count on headers or sessions based token exchange to keep you safe. 3) In an updated blog article, Bill Patrianakos outlines a solution that looks really good. It is written from the perspective of a client side app developer> See http://billpatrianakos.me/blog/2013/09/12/securing-api-keys-in-a-client-side-javascript-app/.


(Nailson Martins) #6

Wow @jclish, that was a heavy dish! thanks for sharing this article :wink:


(Jourdan Clish) #7

You are very cool for thinking about security in the IoT. I used to have SO much fun with remote controllable power strips…


(Jourdan Clish) #8

How I got the example from the book working on local mac and heroku:

Download the zip file from github. Extract it.

X-Code Side:

Follow the .pdf book instructions exactly, they are clear and concise. I only had to do one change to get it working.

  1. In HUMRailsAFNClient.m: Changed
    return [self GET:@"events/nearest"
    to
    return [self GET:@“events/nearests”

You can set up X-code schemes as the book recommends so you can use localhost for the debug build target and your heroku deployment for your alpha testing.

RoR Side:

It works locally out of the box (zip file), I still never have gotten the tests to pass and I am sure that is me. To get it working on Heroku -

  1. in Gemfile added:

gem 'bourbon’
gem 'neat’
gem ‘jquery-rails’

  1. Locally compiled the assets.

Then it pushed OK.

To get it working with the App -

  1. Change all references to ‘tb-device-token’ to ‘X-DEVICE-TOKEN’
  2. In application_controller.rb add:
    skip_before_filter :verify_authenticity_token, if: :json_request?

after

protect_from_forgery with: :null_session.

That leaves you a bit insecure but that is what I am working out……