3 ms·
"salting" also prevents brute-forcing. Assuming a bare-basics implementation (20-char salt in config file, 20-char salt per user, prepended to the password), th
by jmillikin 17y ago
"salting" also prevents brute-forcing. Assuming a bare-basics implementation (20-char salt in config file, 20-char salt per user, prepended to the password), the only way an attacker can brute-force passwords in a reasonable timeframe is to compromise the server itself. At that point, it would be just as easy to make the login form mail him passwords.
Merely choosing a slower digest doessn't help, because the digest would have to be extremely slow (minutes or hours per password) to prevent somebody from running it against "password", "12345", etc for every row in the table. And that's the only kind of attack worth preventing -- if somebody can brute-force a 20-character alpha-num-symbol password in realtime, your choice of digest algorithm is irrelevant.
- tptacek 17y agoIf you can't understand the significance of these two results (and this is with the default cost factor for BCrypt), you're just arguing to hear yourself talk. t1 = Time.now.to_i 100.times { BCrypt::Password.create("ugh8&eat") } puts Time.now.to_i - t1 => 12 t1 = Time.now.to_i 100.times { Digest::SHA1.hexdigest("ugh8&eat") } puts Time.now.to_i - t1 => 0 I could raise the number of iterations to bring SHA1 above the measurement floor, but I don't want to lock my computer up with pointless BCrypt cycles.
- jmillikin 17y agoUsing these numbers, it would take your computer roughly 12 years to check 32M passwords against that string. That's a long time, but feasible (with additional power), and more specialized systems can bring it within reach. In contrast, assuming a 40-character (20 in config, 20 in database) alphanumeric salt, an attacker would have to perform 704423425546998022968330264616370176 digests per row to check 32M passwords. Unless you believe that is an insufficient barrier, implementing BCrypt is merely degrading the user experience (12-second logins? come on) for no real improvement.
- harpastum 17y agoI think that the salient detail is this: t = Time.now.to_i 1000000.times {Digest::SHA1.hexdigest("ugh8&eat")} puts (Time.now.to_i - t).to_s =>3 Sure, 120ms is a bit long, but I think it would be beneficial to security to require more than 3µs. Edit: I match my parent's problem with 32M checks taking 12 years with my personal computer taking 132.86 seconds to calculate 32M SHA1s.
- jmillikin 17y agoThere are lots of ideas which are beneficial, but not particularly useful. For example, requiring passwords to be at least 120 characters would (in theory) make passwords more difficult to compromise, but in practice users are just going to type "password" 15 times. Increasing the digest time prevents an attacker with simultaneous access to the server and database from cracking very weak passwords, but at the cost of tripling or quadrupling how much time each request takes. There are some cases where this could be useful -- for example, running a dissident website in an authoritarian country -- but it's user-hostile to implement it anywhere else.
- tptacek 17y agoCalculating a BCrypt hash with the default cost factor takes about as long as reading an uncached file off a conventional filesystem. What a silly thing to try to optimize. Really? It's killing you to spend 100ms on password hashing? Ok, dial it down to 50ms. BCrypt is tunable.
- rpbertp13 17y agoHis computer is taking 12 seconds for 100 iterations. The time spent checking the password would be more like 120 ms, totally in the order of a decently fast http request.
- deleted 17y ago[deleted]
- DarkShikari 17y agoIf the attacker can get the list of password hashes, what's stopping him from getting your salts too? You're basically just splitting the passwords into two components--two-factor security--except that two-factor security requires two separate concepts, not simply requiring two passwords.
- jmillikin 17y agoSalts are usually stored in two components; one is in the database and unique per row, to prevent cracking multiple rows at once. The other component is in a config file in the server -- it adds a constant number of bytes to the input for any brute force attempt. If an attacker can achieve a root login to your server, then they can read your config file, but they can also just change the login form to email them passwords. For this reason, most password defense is aimed at the assumption that the attacker gained access to the database server, but not the webserver. Historically, this has proven to be a safe assumption.
- mikebo 17y agoIf your webserver machines are so secure, why put them in the database at all? Just store the passwords on disk there, rsync the password file across all machines and you're set. I kid, but I really think you and tptacek just have different standards. tptacek's is higher.
- tptacek 17y agoLots more web app flaws allow you to read arbitrary files than allow you to get a shell on the app server. There are cases where SQL Injection by itself is sufficient to get the contents of files. I think that's what bothers me most about using SHA1(k, nonce, password) as a hash. Well, that and the obnoxious trick question.
- ErrantX 17y agoIf your webserver machines are so secure, why put them in the database at all? You do put them on a web server. It just happens to run software optimized for extracting a particular entry from a large data set :) Ironically the way you suggest is more secure: because to compromise it (assuming the web app is out of the equation for the moment) requires a system exploit. Whereas you have the added complexity of the database as an additional weak point. EDIT: im confused about the downvote.. what in particular appears wrong (so I can explain it). Having Database software certainly lowers security on any system :) it's another failure point (any good security text book will explain that)