git ssb

0+

dangerousbeans / %aPBe2k3ugtjBr4rrsU1…



Tree:
πŸ“„.gitignore
πŸ“„CHANGELOG
πŸ“„COPYING
πŸ“„Gemfile
πŸ“„README
πŸ“„Rakefile
πŸ“ext
πŸ“lib
πŸ“spec
README
1= bcrypt-ruby
2
3An easy way to keep your users' passwords secure.
4
5* http://bcrypt-ruby.rubyforge.org/
6* http://github.com/codahale/bcrypt-ruby/tree/master
7
8== Why you should use bcrypt
9
10If you store user passwords in the clear, then an attacker who steals a copy of your database has a giant list of emails
11and passwords. Some of your users will only have one password -- for their email account, for their banking account, for
12your application. A simple hack could escalate into massive identity theft.
13
14It's your responsibility as a web developer to make your web application secure -- blaming your users for not being
15security experts is not a professional response to risk.
16
17bcrypt allows you to easily harden your application against these kinds of attacks.
18
19== How to install bcrypt
20
21 sudo gem install bcrypt-ruby
22
23You'll need a working compiler. (Win32 folks should use Cygwin or um, something else.)
24
25== How to use bcrypt in your Rails application
26
27=== The +User+ model
28
29 require 'bcrypt'
30
31 class User < ActiveRecord::Base
32 # users.password_hash in the database is a :string
33 include BCrypt
34
35 def password
36 @password ||= Password.new(password_hash)
37 end
38
39 def password=(new_password)
40 @password = Password.create(new_password)
41 self.password_hash = @password
42 end
43
44 end
45
46=== Creating an account
47
48 def create
49 @user = User.new(params[:user])
50 @user.password = params[:password]
51 @user.save!
52 end
53
54=== Authenticating a user
55
56 def login
57 @user = User.find_by_email(params[:email])
58 if @user.password == params[:password]
59 give_token
60 else
61 redirect_to home_url
62 end
63 end
64
65=== If a user forgets their password?
66
67 # assign them a random one and mail it to them, asking them to change it
68 def forgot_password
69 @user = User.find_by_email(params[:email])
70 random_password = Array.new(10).map { (65 + rand(58)).chr }.join
71 @user.password = random_password
72 @user.save!
73 Mailer.create_and_deliver_password_change(@user, random_password)
74 end
75
76== How to use bcrypt-ruby in general
77
78 require 'bcrypt'
79
80 my_password = BCrypt::Password.create("my password") #=> "$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa"
81
82 my_password.version #=> "2a"
83 my_password.cost #=> 10
84 my_password == "my password" #=> true
85 my_password == "not my password" #=> false
86
87 my_password = BCrypt::Password.new("$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa")
88 my_password == "my password" #=> true
89 my_password == "not my password" #=> false
90
91Check the rdocs for more details -- BCrypt, BCrypt::Password.
92
93== How bcrypt() works
94
95bcrypt() is a hashing algorithm designed by Niels Provos and David Mazières of the OpenBSD Project.
96
97=== Background
98
99Hash algorithms take a chunk of data (e.g., your user's password) and create a "digital fingerprint," or hash, of it.
100Because this process is not reversible, there's no way to go from the hash back to the password.
101
102In other words:
103
104 hash(p) #=> <unique gibberish>
105
106You can store the hash and check it against a hash made of a potentially valid password:
107
108 <unique gibberish> =? hash(just_entered_password)
109
110=== Rainbow Tables
111
112But even this has weaknesses -- attackers can just run lists of possible passwords through the same algorithm, store the
113results in a big database, and then look up the passwords by their hash:
114
115 PrecomputedPassword.find_by_hash(<unique gibberish>).password #=> "secret1"
116
117=== Salts
118
119The solution to this is to add a small chunk of random data -- called a salt -- to the password before it's hashed:
120
121 hash(salt + p) #=> <really unique gibberish>
122
123The salt is then stored along with the hash in the database, and used to check potentially valid passwords:
124
125 <really unique gibberish> =? hash(salt + just_entered_password)
126
127bcrypt-ruby automatically handles the storage and generation of these salts for you.
128
129Adding a salt means that an attacker has to have a gigantic database for each unique salt -- for a salt made of 4
130letters, that's 456,976 different databases. Pretty much no one has that much storage space, so attackers try a
131different, slower method -- throw a list of potential passwords at each individual password:
132
133 hash(salt + "aadvark") =? <really unique gibberish>
134 hash(salt + "abacus") =? <really unique gibberish>
135 etc.
136
137This is much slower than the big database approach, but most hash algorithms are pretty quick -- and therein lies the
138problem. Hash algorithms aren't usually designed to be slow, they're designed to turn gigabytes of data into secure
139fingerprints as quickly as possible. bcrypt(), though, is designed to be computationally expensive:
140
141 Ten thousand iterations:
142 user system total real
143 md5 0.070000 0.000000 0.070000 ( 0.070415)
144 bcrypt 22.230000 0.080000 22.310000 ( 22.493822)
145
146If an attacker was using Ruby to check each password, they could check ~140,000 passwords a second with MD5 but only
147~450 passwords a second with bcrypt().
148
149=== Cost Factors
150
151In addition, bcrypt() allows you to increase the amount of work required to hash a password as computers get faster. Old
152passwords will still work fine, but new passwords can keep up with the times.
153
154The default cost factor used by bcrypt-ruby is 10, which is fine for session-based authentication. If you are using a
155stateless authentication architecture (e.g., HTTP Basic Auth), you will want to lower the cost factor to reduce your
156server load and keep your request times down. This will lower the security provided you, but there are few alternatives.
157
158== More Information
159
160bcrypt() is currently used as the default password storage hash in OpenBSD, widely regarded as the most secure operating
161system available.
162
163
164For a more technical explanation of the algorithm and its design criteria, please read Niels Provos and David Mazières'
165Usenix99 paper:
166http://www.usenix.org/events/usenix99/provos.html
167
168If you'd like more down-to-earth advice regarding cryptography, I suggest reading <i>Practical Cryptography</i> by Niels
169Ferguson and Bruce Schneier:
170http://www.schneier.com/book-practical.html
171
172= Etc
173
174Author :: Coda Hale <coda.hale@gmail.com>
175Website :: http://blog.codahale.com
176

Built with git-ssb-web