git ssb

0+

dangerousbeans / %aPBe2k3ugtjBr4rrsU1…



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

Built with git-ssb-web