In my Rails app users are submitting sensitive username/password combinations to their webshop systems so my app can interact with them. I need to enforce a high data-at-rest security for these data.

From what I read in e.g. this answer the attr_encrypted gem is a good solution for encrypting model fields in MongoDB. But I don't like the fact that functionality as well as encrypted data and keys are handled/stored on a single server. And I would like to use a unique key for each encryption. So I am considering to store usernames on one server, encrypted passwords on a second and keys on a third.

Do you see any red flags in this approach?

This is how I handle the users submission of a new webshop:

1) My main server receives webshop data from a user and saves the username, but it forwards the password:

def create_webshop
  webshop = current_user.webshops.create(username: params[:username])

2) My password server receives the password and generates a key. It then encrypts the password and saves it, but forwards the key:

def create_password
  key              = SecureRandom.base64
  password         = AESCrypt.encrypt(params[:password], key)
  password_holder  = PasswordHolder.create(webshop_id: params[:webshop_id], password: password)
  render :json => {}, :status => :ok

3) My key server receives the keyand saves it:

def create_key
  KeyHolder.create(password_holder_id: params[:password_holder_id], key: params[:key])
  render :json => {}, :status => :ok

This is how I get the password for a webshop:

1) My main server queries for the password to a given webshop_id:

def get_password(webshop)
  password_response = HTTParty.get("https://passwords.mydomain.com/get_password?webshop_id=#{webshop._id}")
  password          = JSON.parse(password_response.body)["password"]
  # Do stuff...

2) My password server receives the password query and queries for the key to a given password_id:

def get_password
  password_holder = PasswordHolder.where(webshop_id: params[:webshop_id]).first
  key_response    = HTTParty.get("https://keys.mydomain.com/get_key?password_holder_id=#{password_holder_id._id}")
  key             = JSON.parse(key_response.body)["key"]
  password        = AESCrypt.decrypt(password_holder.password, key)
  render :json => {:password => password}, :status => :ok

3) My key server receives the key query and returns the key:

def get_key
  render :json => {:key => KeyHolder.where(password_holder_id: params[:password_holder_id]).first.key}, :status => :ok

My password server then decrypts the password and returns it to my main server.

  • What is it that you are trying to protect against? Malware on your main server seems to have access to all the data despite all of these efforts. Are you strictly worried about someone getting a dump of a database? Someone get a disk drive image? Other? Oct 12 '15 at 18:34
  • PS: Keep in mind that questions that are closed as being unclear can frequently be updated and reopened. You can also use the comments to ask for advice about improving your questions if you are unsure how to update them. Oct 12 '15 at 18:36