Gaurav Shah
Gaurav Shah

Reputation: 5279

rails storing password in a session

I have a rails app that makes web api call , the rails app by itself doesn't have any database or userstore. Every api call needs to be sent username and password for each request.

I would like to provide an authentication mechanism for the rails app. I am planning to do it this way :

  1. Show a login page
  2. Get the username and password
  3. Store the username and password
  4. Perform a manual authentication either via warden.authenticate or authlogic.something ( or may be even that is not required can just check if session has something stored )
  5. And then when user does something I pass the username and password that was stored earlier.

Now my problem is where do I store the password ? If I use session I cannot use cookie store obviously , I can use session_store = :active_record_store but not sure if its safe , also I don't have any database as of now so why should I create one just for session ? Is there any other mechanism to store passwords within a session ? (safe way obviously )

Earlier rails had :

But now both seems to be removed. So any other solution ?

Notes from answers :

  1. Storing encrypted passwords won't work since I need the raw password to be sent to server while making api calls.
  2. I have no control over the API , so I cannot change its authentication.
  3. There is no user profile maintenance on rails app. Everything managed by API calls.

I finally thought to implement custom memory store but it seems to throw stackoverflow error. I got the code from https://rails.lighthouseapp.com/projects/8994/tickets/1876-uninitialized-constant-actioncontrollersessionmemorystore

require 'action_dispatch'
module ActionDispatch
module Session
class CustomMemoryStore < ActionDispatch::Session::AbstractStore
  GLOBAL_HASH_TABLE = {} #:nodoc:

  private
    def get_session(env, sid)
      sid ||= generate_sid
      session = GLOBAL_HASH_TABLE[sid] || {}
      session = AbstractStore::SessionHash.new(self, env).merge(session)
      [sid, session]
    end

    def set_session(env, sid, session_data)
      GLOBAL_HASH_TABLE[sid] = session_data
      return true
    end
  end
 end
end
Steptools3::Application.config.session_store :custom_memory_store, :key => '_some_xyz'

Upvotes: 6

Views: 3007

Answers (4)

miaout17
miaout17

Reputation: 4875

I will try to analysis your choices:

If Server is hacked with CustomMemoryStore

Consider the following scenario:

  • 4 Users A, B, C, D is logged in.
  • Your server is hacked. The hacker obtains control of server.
  • D did some operation.
  • You found that your server is hacked, and repaired your system.

With CustomMemoryStore, the hacker can get passwords of all users. It’s not too hard to inject some logic into running Rails process, or dump the memory and analysis. Storing password in ActiveRecord, MongoDB, Redis has similar problem.

If Server is hacked with CookieStore?

What if the previous scenario occurs and you are using CookieStore?

Let’s review the mechanism of CookieStore:

  • Server has a secret key to sign & verify session.
  • Each time when browser sends a request, server decrypts the session, modify the data, sign the session, and send the session to browser in the cookie.

In other words, hacker cannot get the password from the cookie or from the secret key. He needs both cookie and secret key to stole the password.

In this scenario, the passwords of A, B, C are safe. Only D’s password will be stolen by Hacker. You can minimize the damage by repairing the system ASAP.

The Problem of CustomMemoryStore

Besides the security problem, I know you are aware of that CustomMemoryStore is not scalable. However, the problem might be bigger than you think. You will send request to other web services in your controller action, it will block your entire server if the remote service is slow or down. It might be painful even if you have only concurrent 1~10 users.

Even if you decide to run your application on single server, you can start multiple rails process with Passenger or Unicorn. CustomMemoryStore denies these options.

Client Security Concern

If the concern is if cookie is stolen from browser side, you can consider EncryptedCookieStore. It encrypts the session and store in the client cookie. You cannot get password if you have only cookie or the key. You need both cookie and the key to decrypt the password.

What’s the key problem?

EncryptedCookieStore is more secure because it stores encrypted password in user’s cookie, and the secret key is only available on the server. The hacker cannot get password if he only have the cookie or the secret key -- He needs both.

Of course, you can implement similar logic with CustomMemoryStore. For example, store encrypted password in server memory and the individual key is in the cookie. If you still decide to store encrypted password on the server, I will recommend to use Redis for storage. It's simple and fast compared to MySQL and MongoDB. CustomMemoryStore is not suggested because of scaling issue.

Other suggestions

Password of other system is very sensitive data, you should be very careful to deal with security problem. If it’s a public service, you should write your Term of Service and Disclaimer agreement very carefully. Besides, you should run your services with HTTPS.

TL;DR

  • Use OAuth if you can (Well, I know you can't)
  • EncryptedCookieStore should be simple and secure.
  • If you decide to store password on the server, please encrypt it and store the secret key on client side (cookie).

Upvotes: 1

nathanvda
nathanvda

Reputation: 50057

You could try using Redis as a session store. We use rails3-redis-session-store gem. The source can be found here.

It is very easy to setup, and sessions expire automatically, which makes it safe. Example config:

YourApp::Application.config.session_store :redis_session_store,
                                          :db => 0,
                                          :expire_after => 10.minutes,
                                          :key_prefix => "your_app:session:"

An alternative would be to use dalli, and thus use memcached as the backend.

Hope this helps.

Upvotes: 2

Harish Shetty
Harish Shetty

Reputation: 64363

The session cookies are encrypted using the session key. Your data should be secure as long as you keep your session key strong (128 char) and safe.

ActionController::Base.session = {
  :key         => '_foo_bar_session',
  :http_only   => true,
  :secret      => 'dldkdke420934indsknknkfsnh318u84e9u49832dfkdsajdsk'
}

If you want to store the authentication details beyond a browser session then you can store them in signed, permanent cookies.

cookies.permanent.signed[:user_credentials] = [login, password]

The signed cookies are accessed like regular cookies:

cookies[:user_credentials]

Make sure you set a strong cookie_verifier_secret in your initializer file.

ActionController::Base.cookie_verifier_secret ='dskjkjfdshfddsfkhkr3898398430943'

Reference

Signed and Permanent cookies in Rails 3

Upvotes: 1

creativetechnologist
creativetechnologist

Reputation: 1462

I would recommend taking the next step and setting up a simple database and save a lot of hassle for yourself and the user, what happens when the user wants to return to the site, they will have to re-register.

I find Devise is awesome for this purpose and very simple to integrate.

If there is an issue where you don't want to have a classic database server running you may want to look at MongoDB

Upvotes: 1

Related Questions