Rails: storing encrypted data in database - ruby-on-rails

I want to encrypt database because confidential data is being stored. I use mongodb with mongoid. It possible for this kind of database? And what alternatives can you recomend, if it is not?
P.S. Main purpose is: if anybody hack the server and steal DB, it would be unencryptable.
UPDATE: thanks for nickh, I found very many soultions for ActiveRecord, but nothing for Mongoid and other Mongo clinets. It would be great to find some soultion for Mongo and Mongoid!

I have gotten attr_encrypted working with Mongo and Mongoid. It takes only a few tweaks.
Make sure that all of the encrypted_ fields that are automatically created by attr_encrypted are explicitly created in the model. For instance, if you have:
attr_encrypted :email, :key => 'blah blah blah', :encode => true
you need to have:
field :email, :type => String
field :encrypted_email, :type => String
Also notice you need to tell it to encode the encrypted string otherwise Mongo will complain loudly.
Lastly, if you're encrypting a hash, do this:
field :raw_auth_hash, :type => Hash
field :encrypted_raw_auth_hash, :type => String
attr_encrypted :raw_auth_hash, :key => 'blah', :marshal => true, :encode => true

I've had a lot of success with the attr_encrypted gem. However, I've only used it with ActiveRecord. I don't know if it works with MongoMapper or Mongoid.
Regardless of how you implement this, I strongly recommend only encrypting certain fields. Don't encrypt every field in every table. Doing that will make it difficult to use associations, search using LIKE, etc.

Try the mongoid-encrypted-fields gem - it is seamless as it handles encryption using mongoize/demongoize methods.
Just define your field like:
field :ssn, type: Mongoid::EncryptedString
Then you can access it like normal, but the data is stored encrypted.

http://ezcrypto.rubyforge.org/
Using postgreSQL with the ezcrypto gem atm - works reasonably well although there are limitations in using associations between models with encrypted fields (this maybe down to my inability to find the correct up-to-date fork of this project).
The encrypted fields are stored in the postgreSQL database as the BYTEA datatype and will usually require for single quotes to be escaped (another issue with the plugin),
PostgreSQL does also have access to its own encryption / decryption modeul 'pgcrypto' which also returns a BYTEA datatype. Not sure how this would integrate with Rails activerecord and associations between models (probably badly :D).

I use MongoDB in an app with the Mongoid ruby adapter. Ryan Bates (the demigod of Rails) recently made an outstanding railscast on this very issue http://railscasts.com/episodes/250-authentication-from-scratch.
I'm using this in a MongoDB app and it works perfectly for encrypting data. His tutorial video is mostly for encrypting passwords, but you can adapt it to any other field value you want.
I also have used attr_encrypted with much success but I'm not sure if it will work with MongoDB; only used it with ActiveRecord.

Related

Unable to fetch ActiveRecord models based on Rails 7 encrypted field

I have a Rails 7 app and I decided to encrypt a field on an ActiveRecord model. I took the following steps:
bin/rails db:encryption:init
rails credentials:edit --environment development and added the keys there
Added a encrypts :name to the model
Now when I query the model by doing SomeModel.where(name: 'blah'), it doesnt return any records even though the record is in the DB.
I can however:
Do SomeModel.all and verify that the record exists and has the value 'blah' that I'm querying with
Make the query work if I change encrypts: name to encrypts: name, deterministic: true
What am I doing wrong that's making the queries fail on non-deterministically encrypted fields?
If you want to query the encrypted attribute, you need to make the encryption deterministic.
So encrypts :name, deterministic: true

How to set composite key in Rails application

I am using 'foriegner' gem in my application to set primary key, now i am in a situation to
set composite primary key in a table.
I searched the web for this, but could not able to find a clear solution for this.
Please suggest me if its possible to set composite keys in rails application using foreigner gem or by any other means.
Note : I am using Postgres
thanks.
ActiveRecord
There is a gem called composite_primary_keys and integrates these features quite will for ActiveRecord.
It supports a wide array of ActiveRecord versions.
# Gemfile
gem 'composite_primary_keys', '=<version for your AR version>'
Use it like the following example:
class Membership < ActiveRecord::Base
self.primary_keys = :user_id, :group_id
end
membership = Membership.find([1,1]) # composite ids returns single instance
# => <Membership:0x39218b0 #attributes={"user_id"=>"1", "group_id"=>"1"}>
I am happily using it in production, keeping my schema clean and tidy.
Better alternative: Sequel
As always, if you are looking for a great Ruby + PostgreSQL solution, look no further than jeremyevans/sequel.
It comes with a vast amount of features, including composite primary keys. Out of the box.
So if you are starting a new project (on PostgreSQL obviously), save yourself the headache of ActiveRecord and go with Sequel.
class Post < Sequel::Model
set_primary_key [:category, :title]
end
Short answer: DON'T use composite PKs in Rails (unless you are forced to do so because of a legacy DB).
While there might be solutions with gems that work (currently) this is just not the way that ActiveRecord works. I'd also not use composite PKs outside of Rails unless there is a really good reason. They make a lot of things more complicated.
But: nothing prevents you from having what you think of a a composite primary key as an alternative key and have the Rails default PK (postgres: pseudotype 'serial' which draws its values from a sequence). Just make sure that you add a unique index for those columns that make up your key.

Rails: how do I use question marks in a model?

We have a field in our mongodb database called "failed?", including the question mark. Sometimes when I access that field, I get the value in the database, and sometimes I get null. I'm looking to understand what should happen a little bit more in order to debug this. So, can you have a question mark in a field name in a model, like so:
field :failed?, :type => Boolean, :default => nil
or am I in for a world of trouble. Assuming I already have this in the database and have to work with it, how should I get the fields out.
Environment: Rails 3.1, JRuby, Mongoid.
It's most likely a Mongoid bug as question marks in field names are valid in MongoDB. If I had to take a guess, it could be a weird conflict with the automatic <field>? that are created by Mongoid.
The easiest way to work around this would be to try accessing it through the raw hash that is pulled out from MongoDB, you can access it with model.attributes["failed?"]. If you still have issues, then likely it's a MongoDB driver problem.

Creating readable models in rails

I have just started with Rails and coming from a .net background I find the model inheriting from ActiveRecord is hard to understand, since the don't contain the corresponding attributes for the model. I cannot imagine a new developer exposed to a large code where the models only contains references to other models and business logic.
From my point of view the DataMapper model is much easier to grasp but since ActiveRecord is the defacto standard it feels weird to change the ORM just for this little problem.
DataMapper
class Post
include DataMapper::Resource
property :id, Serial # An auto-increment integer key
property :title, String # A varchar type string, for short strings
property :body, Text # A text block, for longer string data.
property :created_at, DateTime # A DateTime, for any date you might like.
end
ActiveRecord
class Post < ActiveRecord::Base
end
I'm not sure if this is an issue and that people get used to the models without attributes, or how does experienced rails user handle this?
I don't think using the database manager or looking at loads of migrations scripts to find the attributes is an option?
Specifying attr_accessible will make the model more readable but I'm not sure if it's a proper solution for my problem?
Check out the annotate_models plugin on github. It will insert a commented schema for each model in a comment block. It can be installed to run when migrate is.
You don't have to "look at loads of migration scripts to find the attributes" - they're all defined in one place in db/schema.rb.
A few tips:
Load up the Rails console and enter
Post.column_names for a quick
reminder of the attribute names.
Post.columns gives you the column
objects, which shows the datatypes
db/schema.rb contains all the
migration code in one place, so you
can easily see all the column
definitions.
If you are using a
decent editor/IDE there should be a way to
allowing you to jump from the model file
to the migration file. (e.g. Emacs
with ROR or Rinari)

ActiveRecord without setting up database tables? (declarative like Django)

In Django, you fully describe your models in models.py. In Rails with ActiveRecord, you describe part of a model in in the /models directory, and part of it in migrations. Then ActiveRecord introspects model properties from the existing database tables.
But I find migrations, columns, and tables to be a headache.
How can I do like Django -- just declare all model properties instead of introspecting them from the database tables?
And for extra credit, explain where and why this would be a bad idea. :)
If you hate on Migrations, try going NoSQL. No migrations!
So you'd just add properties to your document when you need them. In your code, handle the fact that they may not exist and bam!
I took the following model definition (notice you don't inherit form activerecord) from a blog about tekpub Also recommend the Herding Code podcast
class Production
include MongoMapper::Document
key :title, String, :required => true
key :slug, String, :unique => true, :required => true, :index => true
key :description, String
key :notes, String
key :price, BigDecimal, :numeric => true
key :released_at, Date, :default => Date.today
key :default_height, String, :default => '600'
key :default_width, String, :default => '1000'
key :quotes, String
#royalty info
key :producers, String
timestamps!
end
Try the auto_migrations plugin. I don't think it's a bad idea for development, but I would switch to migrations after going to production when there is critical data in the database.
You may also be interested in replacing ActiveRecord with DataMapper, which works in Rails 3. It has the style you are talking about, with the description of the data fields of a model in the model code instead of a separate database schema file.
I think DataMapper is what you are asking for. Once set up, you'd either use DataMapper.auto_migrate! or DataMapper.auto_upgrade!. The former will drop tables if they exists before creating them, thus destroying any data. That would be bad for production. The latter is how you avoid losing data, and should be just fine for production.
Without knowing exactly what its doing, I'd guess it's inspecting tables during startup to determine whether to make database changes. That can drag down start up time, especially with a lot of models/tables. Which is actually one of the good reasons to consider NoSQL - specifically Mongo as mentioned above. It's fast. Really fast, and thus the start up cost is much, much less. MongoMapper is the way to go. The tekpub blog post is a must read.
I first heard about DataMapper in reading about Merb, so it makes sense that it's in rails 3. I don't know whether you may be able to get it working in rails 2.x.

Resources