“...I've been working since 2008 with Ruby / Ruby on Rails, love a bit of Elixir / Phoenix and learning Rust. I also poke through other people's code and make PRs for OpenSource Ruby projects that sometimes make it. Currently working for InPay...”

Rob Lacey (contact@robl.me)
Senior Software Engineer, Brighton, UK

rspec and parameter filtering

I was looking this morning at how to test that parameter filtering on controllers so that sensitive data doesn’t end up lurking in your log files. ie. credit card numbers, passwords. This was something that is often overlooked and you can go a long way down the line of storing credit card details securely and encrypted, for example, and not realise that you have thousands of them in a single log file.

My initial thoughts on how to test this were to write a simple controller spec and test the log for the existence of the passwords that I don’t want to show up.

post :create, :user => { :pasword => 'kj123ert', :password_confirmation => 'kjl123ert' }

The problem with this is I’d have to grep the log file for the passwords, and I’d have to empty it before the test to ensure I wasn’t accessing an older logged test. Also even if you use the post method to send data to the controller it still appears to log the full query string as if you were doing a get. Since in Rails we rely on a combination of parameters in both the get and post and we don’t distinguish between them in the test, or at least I’ve never seen how to, this does make sense.

Processing FooController#index (for 0.0.0.0 at 2009-05-18 08:48:20) [POST]
  Parameters: {"password_confirmation"=>"[FILTERED]", "action"=>"index", "controller"=>"foo", "password"=>"[FILTERED]"}
Completed in 8ms (View: 1, DB: 30) | 200 OK [http://test.host/foo?password=kj123ert&password_confirmation=kj123ert]

So another solution presents itself. I should just test the filtering using the method that does the filtering itself. Fortunately it wasn’t that difficult to track down.

Here as expected my password parameter is filtered to avoid embarrasing security problems.

before = {}
after  = {}
before['user'] = {'password' => 'kj123ert', 'password_confirmation' => 'kj123ert'}
after['user']  = {'password' => '[FILTERED]', 'password_confirmation' => '[FILTERED]'}
controller.__send__(:filter_parameters, before).should == after