Beating the authentication horse (dead yet?)

Guys,

I’m frankly overwhelmed by the number of Rails authentication options(?)
out there…from ActiveRBAC to acts_as_authenticated to LoginEngine and
so on…so many options, yet on resource I’ve found really distinguishes
between each.

This is sad, as authentication and user management is really an area
where some Rails simplicity pixie dust could be a real boon to
developers. Can anyone point me in the direction of a good comparison,
or can you recommend a particular approach? I’m very wary of chosing the
coat tail to ride and not realizing it until two weeks after grabbing
ahold…

Thanks!

B.A.

B.A. Baracus: I thought you weren’t crazy no more?
Murdock: Only on paper.

On Jul 4, 2006, at 6:55 PM, BA Baracus wrote:

developers. Can anyone point me in the direction of a good comparison,
or can you recommend a particular approach? I’m very wary of
chosing the
coat tail to ride and not realizing it until two weeks after grabbing
ahold…

Hey B.A. - an acute observation. Perhaps there are so many
authentication systems because they are so simple to implement? The
proliferation of options doesn’t imply the need to choose :slight_smile:

jeremy

I have used acts_as_authenticated a number of times, I am pretty happy
with
it. It’s very adaptable and pretty much stays out of the way. Just
experiment a little and see what approach you like best. ActiveRBAC is
pretty smooth too.

On 5 Jul 2006 01:55:56 -0000, BA Baracus
[email protected]

On Tue, 4 Jul 2006 19:13:34 -0700, Jeremy K. wrote:

Hey B.A. - an acute observation. Perhaps there are so many
authentication systems because they are so simple to implement? The
proliferation of options doesn’t imply the need to choose :slight_smile:

Except to the extent that it makes developing compatible components
difficult, because you can’t rely on any one authentication scheme.

But it’s early days with Rails yet; it’s my personal hope that a few
complementary schemes will win the natural-selection game, and perhaps
they’ll even be compatible. Remember how long it took for even basic
infrastructure like TCP/IP to go from “prevalent” to “omnipresent”? You
might have AppleTalk, token ring, Banyan Vines, Novell, all fighting for
your cabling infrastructure. Rails 1.0 is less than a year old; we’ve
got
time to see what works and what doesn’t.

Jay L.

On Tue, 4 Jul 2006 23:48:28 -0500, David Heinemeier H. wrote:

But it’s early days with Rails yet; it’s my personal hope that a few
complementary schemes will win the natural-selection game, and perhaps
they’ll even be compatible.

Don’t hold your breath. People have chased the component pipe dream
for decades. It hasn’t arrived yet. I don’t think it ever will. I’ve
written about this twice on LT:

Yep, and I respectfully disagreed both times! As I said at the time,
it’s
natural for you to be a pessimist about componentization. After all,
you
were fed up enough with what you found that you rolled your own freaking
framework. But you’re happy with what you created, so you don’t
recommend
that others do the same.

And I do agree that some things are too easily created, and too, er,
difficultly configured, to be true components. But a lot of simple
things
DO make good plugins, just because they’re so simple and everyone wants
to
do them. I’m sure any of us could roll our own form helpers, and before
1.1, we did - yet now we have form_for, and it’s nicer. I think of
authentication in that vein.

In the “real” authentication space, LDAP seems to finally be taking hold
after, what, 13 years of languishing in nice-theory-land. I’ve been
massively wrong before, but I’m willing to bet you that Rails will
converge
on a few common authentication solutions in half that time. Dinner in
2013?

Jay L.

infrastructure like TCP/IP to go from “prevalent” to “omnipresent”? You
might have AppleTalk, token ring, Banyan Vines, Novell, all fighting for
your cabling infrastructure. Rails 1.0 is less than a year old; we’ve got
time to see what works and what doesn’t.

Don’t hold your breath. People have chased the component pipe dream
for decades. It hasn’t arrived yet. I don’t think it ever will. I’ve
written about this twice on LT:
http://www.loudthinking.com/arc/000335.html and
http://www.loudthinking.com/arc/000407.html

Regarding authentication, I’ll strongly encourage people to try
rolling their own. It’s probably simpler than trying to compare the
prepackaged options out there. And you’ll learn a lot about Rails and
filters in the process.

David Heinemeier H.
http://www.loudthinking.com – Broadcasting Brain
http://www.basecamphq.com – Online project management
http://www.backpackit.com – Personal information manager
http://www.rubyonrails.com – Web-application framework

David Heinemeier H. wrote:

Regarding authentication, I’ll strongly encourage people to try
rolling their own. It’s probably simpler than trying to compare the
prepackaged options out there. And you’ll learn a lot about Rails and
filters in the process.

Implementing basic session-based authentication is a breeze (and it’s
covered nicely in the Agile Web D. book). Here’s a few things
to have in mind when creating secure logins and cookie-based
authentication, though. Bear in mind, I’ve only been on rails for a
week, and I’m making assumptions here. :slight_smile:

Storing user data in sessions

You’ll probably want to store the hashed password along with the user ID
in the session data. That way, a session will be rendered invalid if the
password is changed.

Session fixation / session stealing

The ID of an existing, authenticated session is all an attacker would
need to access protected data. There’s a few ways this could happen:

  • The attacker establishes a session with the site (ie, points the
    browser to the site), and reads out the session id from the headers or
    the browser’s cookies. He/she then cons an unsuspecting user to login
    using his session. (in php, this is as simple as a link like
    http://site.com/?PHPSESSID= - i’m not sure if rails even
    supports supplying session ids via url parameters). This is called
    session fixation.

  • Cross-site scripting. There’s a number of ways a malicious user could
    make a javascript execute in your browser, read up on XSS for the
    details. The result? The attacker is able to read data from your
    cookies, including the session ID. Voila, instant backstage pass.

  • Sniffing on shared networks. Use HTTPS if you’re worried about network
    sniffing.

The solution to blocking session fixation is dead simple: change the
session id or start a new session on login.

Making sure the session id is coming from the correct client is a bit
hairier. You could store the ip-adress in the session and verify that
aswell. That’ll make it more secure in many cases, but bear in mind:
some ISPs use proxy servers sharing a pool of ip-addresses, meaning the
requests could come from different ip-addresses. Also, the attacker
could be sitting on a local network sharing the same external
ip-address.

It’s probably safe to assume that there’s something fishy going on if
the User-Agent header string changes from request to request.

Change the session ID on every request if you’re absolutely paranoid,
though that will break concurrent requests.

And remember to clear out stale sessions as often as possible.

Storing logins in cookies

Storing the username and password in a cookie is asking for trouble. If
your site is vulnerable to cross-site scripting, not only would the
attacker be able to retrieve the session id - the clear text password
would be accessible as well. Plus, the clear text password would be
transmitted over the air on each and every request along with the HTTP
headers. Anyone with physical access to the machine would be able to
read the clear text password from the cookies. Don’t store sensitive
data in long-term cookies on shared terminals whatsoever.

In my PHP setup, I use a system with two tables:

users

username
hashed_password

users_login

user_id
remote_address
token
hashed_password
last_seen_at

On authentication check, I first try to find the username and hashed
password in the session. If they’re not present, I check if the username
and a token are provided via cookies. If the token is provided, I try to
get the hashed password from the user_login table with username, ip
address and token as keys. I then check the hashed password against the
real hashed password in the users table. If they match up, the user is
authenticated.

When a user successfully logs in (via the login form), I do two things:

  1. Store the username and hashed password in the session
  2. Unless the user already has a token set in the cookies, I generate a
    new one. The token is a random hash. I set token and username in the
    cookies, and create a new entry in the users_login table.

This solution assumes the user have a static IP-address. If the IP
changes, the user will have to reauthenticate on the next session. Not
much of an inconvenience for my users, but most are on broadband access
with more or less static addresses.

If I change my password, sessions and tokens on other machines would no
longer be valid. IMHO, this is desirable. (I might forget about logging
out of a public access computer, and change my password to ensure that
the old session no longer would be valid)

You could up the paranoia on this solution too… For example, if
authentication fails for a user (wrong password, wrong IP), you could
wipe that users tokens from the users_login table to reduce the chance
of a successfull hacking attempt, at the expense of having the user
relogin on the next session.

There’s no such thing as bulletproof security. The trick is to add as
much complication as you can to the authentication process without
inconveniencing the users too much. It all depends on how sensitive the
data in your application is, and how much the attacker would gain on
getting access (ie, how much effort he/she is willing to put in). Also,
remember: Less Software. An authentication scheme is as strong as it’s
weakest link, ie. the ugliest bug.

Inge Jørgensen
web developer/designer
[email protected]
[email protected]

Thanks to all for the discussion. I’ll likely just go with
acts_as_authenticated and build the features I need around it. I
appreciate your help.

B.A.

On 7/5/06, Inge Jørgensen [email protected] wrote:

The solution to blocking session fixation is dead simple: change the
session id or start a new session on login.

On that note, does anyone have a clean approach for changing just the
session id?

My Ruby isn’t quite strong enough to let me enumerate and copy the
data in conjunction with AR::Base.reset_session.

Isak