
The Rails Way: Users and Passwords - sant0sk1
http://www.therailsway.com/2009/8/3/users-and-passwords
======
patio11
Isn't the extra security gained by salting rather illusory? If you lose a copy
of your database, which is one of the two attacks under consideration, any
individual password is discoverable. If you store the password and the salt in
the database, that is all that is needed to play "guess that rainbow table".

If you have someone with access to your server or source control go rogue,
every password entered into the website should be presumed compromised.

(Why attack stuff from your database, necessitating a costly rainbow table,
when you have write access to Ruby code? The most obvious solution to me is
just turning off Rails' feature to strip passwords out of the log, but given
that you can monkeypatch _anything_ you darn well please from _anywhere_ , you
have literally unbounded access to the cleartext params[:password] to steal
any time you darn well please.)

~~~
judofyr
If you include some random data in the salt, it's impossible to create rainbow
tables out of it. Thus the attacker would have to bruteforce every single
password, which will take its time (specially on bcrypt).

Salting doesn't make it impossible, it just takes longer time.

~~~
ajross
Exactly. Salting is a constant factor de-optimization of the password cracking
process. If your users are choosing good passwords (i.e. precomputed table
based attacks don't work) then you don't need it. If they aren't (and they
aren't!) then salting at least gives you some hope that such an attack will be
infeasible for a given attacker's hardware.

In practice, the constant factor can be very large, so this isn't a
meaningless trick.

------
Hexstream
I salt passwords with the first half of the username at the front and the
second half at the back. Is that significantly less secure than generating a
random salt for each user?

~~~
LargeWu
It is if somebody figures out what you're doing, or if you tell them, like you
just did...

The whole point of doing it randomly is that even if somebody figures out the
salt for one user, they would still need to figure it out individually for
every other user too. Using a "system", like you're doing, significantly
decreases the effort required to figure out the salt.

I think it was in WWII where the Americans would intercept the German
broadcasts, which were encrypted by Enigma. But because the Germans routinely
broadcast the same sorts of information in the same format every day - weather
reports, for example, it gave the US a known set of data of limited scope
which significantly improved their chances of breaking the codes. What you are
doing, especially because you're broadcasting it on the internet, is
essentially the same thing.

~~~
cschneid
I disagree. Salts are not secret. The passwords are. The idea is that it just
prevents massive pre-computation attacks, where the same set of precomputed
hashes can be reused. At the point there are salts introduced (different for
each user), there's no way to precompute a huge rainbow table and use it.

So from my un-trained-in-cryptography eyes, the username approach is solid.

~~~
LargeWu
Yes you are correct. I'm not sure what I was thinking there.

------
ianbishop
>> don’t use SHA256 for password hashing, use some algorithm that is designed
to be slow (like bcrypt or scrypt) to make offline password cracking even more
difficult. (dedicated hardware for SHA256 is really fast)

Has anyone ever actually bothered to try implementing something like this over
SHA/MD5?

~~~
jrockway
Uh, yes? Here's how I implement salted digests:

    
    
        my $p = Authen::Passphrase::SaltedDigest->new(
            algorithm   => "SHA-1",
            salt_random => 1,
            passphrase  => "passphrase",
        );
        $p->to_rfc2307;
    

Here's how I implement bcrypt:

    
    
        my $p = Authen::Passphrase::BlowfishCrypt->new(
            cost        => 8,
            salt_random => 1,
            passphrase  => "passphrase",
        );
        $p->to_rfc2307;
    

I save that $p->to_rfc2307 string to the database. When I want to verify the
password, I don't have to worry about the algorithm in use, I just say:

    
    
        my $p = Authen::Passphrase->from_rfc2307( <whatever> );
        $p->check_passphrase("passphrase") # returns true or false
    

Polymorphism is a wonderful thing. If I started using a salted digest and
later wanted to switch to bcrypt, I could easily do that. But of course, I
always just start with bcrypt.

(There is other nice stuff, like a passphrase that never returns true from
check_passphrase, for disabling accounts; and a subclass that stores the
password in cleartext, for debugging.)

I am really shocked that a web framework like Rails requires you to do the
salting manually. I wonder how many people, like the Perlmonks folks, got it
completely wrong.

~~~
cschneid
Rails doesn't do anything password related for you. The common authentication
libraries (plugins) do salt the passwords for you.

------
jgfoot
Good advice, though hardly cutting-edge; wasn't Unix doing salted passwords in
the '70s?

~~~
pavel_lishin
A dumb programmer is born every second; it never hurts to post a public
reminder on how to do something.

~~~
jrockway
It's even better to write a library that ensures that even the dumbest
programmer doesn't fuck it up.

You'd think a web framework would abstract this common task away.

------
pwim
I'm surprised there is not mention of OpenID.

~~~
pavel_lishin
Probably because the article was specifically about salting passwords, not
alternative login solutions.

If I wrote a blog entry about how to perform proper car maintenance to
increase your gas mileage, I wouldn't put in a plug for selling your car and
buying a motorcycle/bicycle.

