T.J. Schuck

80,00 Plaintext Passwords

80,00 Plaintext Passwords

by T.J. Schuck

In the video "80,000 Plaintext Passwords," T.J. Schuck discusses the critical importance of secure password storage in a digital environment. The presentation unfolds in three acts, focusing on historical context, security practices, and open source collaboration. The speaker illustrates common vulnerabilities using a narrative about users who use simplistic passwords, including humorous anecdotes about pets like "Peppercorn."

Key Points:

  • Introduction to Password Security:
    • Schuck emphasizes the necessity for developers to understand security, highlighting that ignorance is not a defense against breaches.
  • Different Security Layers:
    • Discusses the importance of multi-layered security measures and how a single failure can lead to compromises.
  • Password Storage Techniques:
    • Explains the difference between plaintext storage and better methods like hashing.
    • Highlights the inadequacies of reversible encryption, using ROT13 as an example to show how it remains vulnerable.
    • Proposes hashing as a more secure alternative but warns of its own risks, such as the existence of rainbow tables and precomputed hash tables for attackers to exploit.
  • Real Case of Password Extraction:
    • Shares a personal anecdote where he extracted 80,000 passwords from a database in just 87 seconds, demonstrating the ease of password breaches if users follow poor password practices.
  • Mitigating Password Vulnerabilities:
    • Proposes using bcrypt for hashing, which incorporates salts and is designed to be computationally intensive, making it difficult for attackers to utilize brute force methods effectively.
    • Discusses the adaptive cost feature of bcrypt that can be adjusted as computational power increases over time.
  • Transitioning Existing Passwords to Better Security:
    • Describes how to convert existing SHA-1 hashed passwords to bcrypt safely over time without user disruption.
  • Challenges in Open Source Contribution:
    • Shares personal experiences working on the bcrypt-ruby library, highlighting challenges such as dependency management and maintaining code for multiple platforms.
  • Encouraging Collaboration:
    • Concludes by recognizing the value of collaborative open-source work and encourages viewers to engage and support maintainers within the community.

Conclusion:

  • Schuck emphasizes the critical importance of employing secure practices when handling passwords and urges developers to adopt bcrypt, contributing to a culture of security awareness and collaboration in software development.
00:00:28.240 An open source love story in three acts. Just like every good three-act play, we will start with a dramatis personae—a listing of the characters.
00:00:34.000 This is Peppercorn. Peppercorn is one of your user's dogs. Like every good dog owner, as soon as they got Peppercorn, they went and changed every single one of their passwords on all of their sites to 'Peppercorn.' You'll see more of Peppercorn later.
00:00:50.000 This is Mallory. Mallory is an attacker who is going to try to compromise us. We'll come back to Mallory as well.
00:01:03.760 And this is me. My name is TJ Schuck. I am on the Internet everywhere—GitHub, Twitter, etc.—as TJ Shuck. That's my name without the dots and spaces. I work at Harvest, and I'm a developer there. We are online at Harvest.com, and we make the world's best time tracking software.
00:01:17.440 If you do anything where you turn your time into money, like work for an agency, a consultancy, do freelance work, or any kind of thing like that, you should check out Harvest.
00:01:32.640 I have a couple of local points of order. First one is this guy. This is my co-worker, Doug Fales. He currently lives in Montana, but he used to live in Boulder, and the tech community here is apparently tight-knit enough that he knows all of you.
00:01:49.040 So, he rattled off a list of 30 names and told me to meet all of you and say hello, which I promptly forgot. If you do know Doug, come say hi to me, and I will relay the message. To clarify, I'm talking about the human; I don't know who the fish is.
00:02:05.680 Also, if you know the fish, come talk to me because I’d like to give him credit. Additionally, like everyone, we are hiring in both tech roles and non-tech roles. So, if you know anyone that’s looking for a job, tell them to check Harvest.com/careers.
00:02:21.760 We also have remote workers; two-thirds of our company is remote, which is great. Now, for this talk, however, it is notable that I am not a security expert. I'm not a cryptanalyst.
00:02:36.240 I coincidentally have a degree in math, but that doesn't help me here at all. There are people who are actually security experts, cryptanalysts, and they have a lot of fancy letters after their names.
00:02:49.280 They get paid a lot of money to know a lot about this stuff that I don’t know. If you have true fundamental security issues, you should hire one of them. You shouldn’t just listen to this talk and think you’re good.
00:03:06.080 But I have users. We heard earlier about how everyone has a users table. By virtue of the fact that I have users, I need to be a security expert because ignorance isn’t an excuse.
00:03:21.840 If you are compromised and something goes wrong, you can’t say, 'We just didn’t know any better.' That is not an excuse, and if you are the weakest link in the chain of a greater vulnerability, everyone will come back to you and blame you.
00:03:36.240 You cannot just push it away as if you didn’t know any better. So, I have to be a security expert by virtue of having users, and you do too.
00:03:50.240 Back to Mallory. Let’s talk about her attack. Good security is about layers. You should have security at different layers—application level security to protect against things like SQL injection, XSS, and CSRF.
00:04:07.200 You should have infrastructure-level security, which means having a secure data center with physical firewalls between your devices. You should update your version of Bash and do all these things. However, to analyze any individual layer of the security structure, we have to assume that all of them have failed.
00:04:22.960 Mallory can just run this and get a database dump of your database because security has failed. So, we need to do something to mitigate that threat.
00:04:37.760 How are we going to authenticate our users? How are we going to store passwords? The easiest option is plain text: just throw them in the database. You have all your users, they log in with their email, and we have their passwords. Great! This is easy, but it's obviously bad.
00:04:56.640 And no one here is doing that, right? Anyone want to admit to it? Someone here is doing it, and they don’t want to admit it, but they’re doing it because they have reasons.
00:05:08.720 They are running an internal application, so they don’t think it matters, or they run a website that’s for ranking animated GIFs. So, if their passwords get compromised, it doesn’t really matter because people just come rank GIFs on their users’ behalf.
00:05:22.560 But it's bad because users reuse passwords. If there is a breach of your database, they’re going to take 'Peppercorn' from your database and then go over to Gmail and try it.
00:05:37.440 They will try it on banking sites, Facebook, and other places and will get into a lot of those accounts because users use their dog's name as their password everywhere. Therefore, we need some way to obfuscate the data of our passwords because we know that this is bad.
00:05:52.960 The easiest way to obfuscate it is just to encrypt it. So, here are our passwords encrypted. This is a very secure encryption scheme known as ROT13. ROT13 is a Caesar cipher with a key of 13.
00:06:05.760 You take all the letters and shift them by 13. So, an 'A' becomes an 'N', a 'B' becomes an 'O', a 'C' becomes a 'P', etc. That is kind of just for illustrative purposes; it could be DES3, AES256, or anything really.
00:06:16.080 The key to all of those things is that they are reversible. You do something to encrypt them, but then you can do something to get them back out again. They have a secret key in this case; it is 13, but oftentimes it's a more complicated key.
00:06:28.320 However, by virtue of there being that secret key and by the fact that they are reversible, and because we've already had our security compromised, the attacker potentially has access to that key as well.
00:06:38.080 It's often stored in application code or on the server as an environment variable. If they are already into your infrastructure, they can get it. It's also important to note that a malicious actor could just be a malicious employee.
00:06:51.040 If there is a public database dump but it is still encrypted, if you have a large enough organization, there is likely someone nefarious enough who could leak that key. So, even having any way to reverse them is bad.
00:07:03.680 The key here is that encryption is reversible; hashing is irreversible. So using the correct vocabulary here helps make this a little easier to talk about: encryption is reversible; hashing is irreversible.
00:07:13.440 If you take 'Peppercorn' and you hash it, you get some value. If you take 'secret1234' and hash it, you get some value. But if you have some value, even as a good actor, not as an attacker, there’s no way to go backward.
00:07:29.200 So that’s the first key of hashing. The important other thing is that it’s deterministic, which means that if you hash 'Peppercorn', you get a value, and if you hash 'Peppercorn' a second time, you get the same value.
00:07:43.680 If you hash 'Peppercorn' a third time, you get the same value. That’s important because we’re using this for authentication. When users come in with their password in plain text, we need some way to verify it with our stored one.
00:07:59.200 By rehashing it, we can get the output and make sure they're the same, thus authenticating them. It's also important that it's deterministic but not obvious.
00:08:12.960 So when you hash 'Peppercorn', you get the same value both times. However, if you trivially change 'Peppercorn' by capitalizing the first letter, you get a completely different output.
00:08:24.960 Also, if you have an output that is trivially different, just like the least significant bit is off by one, it’s probably completely different from 'CapitalPeppercorn'. So, it is deterministic but not obvious.
00:08:41.760 This is now our table with our hashed passwords. They are all hashed throughout all of this with MD5, just because it's the shortest and fits on slides, but it is the same for SHA-1 and other common hashing algorithms.
00:09:02.560 Now we cannot go backwards, so if there is a dump, our passwords are safe. The problem is what we said earlier: that hashing is deterministic. That’s a double-edged sword because the hash of 'Peppercorn' is always the same.
00:09:17.680 This brings us to the concept of rainbow tables. There are three important points of order here: the first one is that this is the best slide that’s ever been made.
00:09:30.080 The second important point of order is I’ve already turned it into a GIF, and I’ll tweet it to you later. The third important point of order is I am not actually going to talk about rainbow tables right now; I'm going to be talking about lookup tables.
00:09:44.000 A rainbow table is kind of just a specialized case of a rainbow lookup table. It’s just, you know, a longer chain than a lookup table, which is a chain of one.
00:09:58.080 If I was going to talk about lookup tables, my slide would look like this—and that’s boring—so instead you get this one. But you have to know I’m talking about lookup tables.
00:10:10.640 If we have this dump of our database and we have all of these things, we can take the hash and put it into a lookup table. Because that hash is always the same, there are precomputed values where we can see that that hash backwards corresponds to this one.
00:10:23.680 As a proof of concept, we can use the world’s best lookup table, which is Google. You can take a hash and just drop it into Google, and you don’t even have to leave the results page.
00:10:36.400 You can just see what that hash is for. So, we need some way to render all of these precomputed tables obsolete. We need some way to defeat the rainbow. So, when you go to Google and dump it in, you can’t find the output.
00:10:48.080 The easiest way is just to change all the inputs. So, we hash 'Peppercorn'; we know we get this output, and we know that existing tables already include that output.
00:11:01.440 So if we just add a string of nonsense and add some entropy, we’re now giving everyone secure passwords by default. Effectively, their passwords are kind of random, and we can see this works.
00:11:14.640 If we look it up in the lookup table, that value has never been hashed before and is now not in Google, so it’s probably not in lookup tables. We did it; we solved password security. We’re awesome!
00:11:28.960 So yes, attackers won’t be able to look up passwords in a table—that is true. However, it is trivially easy to generate new tables because they can get that altering scheme from your application code or from a malicious employee.
00:11:40.880 You’re storing that little bit of entropy somewhere, usually within your auth check. On this MacBook Air, which is not usually known as a powerhouse of a machine, I can compute 13 million SHA-1 hashes every second.
00:11:54.080 So, if you wanted to make your own table, you could do that very quickly. If you had a 25 million word list, it would take two seconds. If you had a 13 million word list, it would take one second.
00:12:08.320 As a proof of concept, this is where Harvest was. We had a table of users with a table of SHA-1 passwords that had a global salt applied to them. It was just some nonsense.
00:12:23.760 So before anyone else could do it, I decided to attack us. I took a dump, and I then used a very accessible way to extract all these passwords from there.
00:12:36.080 I used freely available software that you can download from the internet trivially. There’s a program called Hashcat; that’s what I used, or John the Ripper, which you can install via Homebrew.
00:12:49.680 It’s not hard to do this, and I needed a dictionary—a word list. I got a 25 million word-long list in about five minutes of Googling. It’s really easy to do these attacks.
00:13:02.320 So, I took the dump of our data, and just for the sake of any Harvest customers here, I did my best to anonymize this data. I only looked at the hashes, so though I kind of know a bunch of passwords, I don’t know your password, and a lot of them have probably been changed anyway.
00:13:16.480 And right there in the middle was 'Peppercorn,' along with 80,000 other passwords from the Harvest database that I got in 87 seconds. So, in less than a minute and a half, I extracted 80,000 passwords.
00:13:29.440 This is not even a majority of our users, but it's definitely enough to do significant damage. I could, if I were a true blackhat attacker, go try to log into all those other services and probably get into many of them.
00:13:43.520 It's important to note that in this crack, I also found these passwords that seem like they're secure. But the programs and word lists are really good. People spend a lot of time developing them because they are useful.
00:13:56.000 So, things like leet speak or alternate character substitutions like making 'universe' with numbers will not work anymore. These programs are smart enough to take the word list and swap out 'I's for '1's and that kind of thing.
00:14:08.320 The middle one looks secure too, until you look down at your keyboard. It’s actually a hardware hack; it’s just marching keys. So, there are a lot of those in there too because they are pretty common.
00:14:20.560 The last one, I don't even know. I don’t know where that’s from. It's not some Game of Thrones character that I haven’t heard of, but by virtue of these things being well architected, they can compute shorter passwords.
00:14:32.480 It's probably just by virtue of the length of it that it got cracked. So, we can do one last attempt. Instead of using a global salt, we can do a per-password salt.
00:14:47.440 Instead of hashing every 'Peppercorn' in our table with the same global one, we can give every individual one a new random bit of entropy, which we then store alongside the password hash in our database.
00:15:04.080 Just to note, I got rid of the email column just for space; you would still have that, or else you wouldn’t be able to look up your people. Knowing the salt is not particularly useful to the attacker, because that is where the complexity is coming from.
00:15:18.880 We also need some way to look it up, and what this does is it just makes it a computational problem. Now, instead of having to generate one table for each user, we would have to generate a table for each user.
00:15:29.840 If you had a thousand users, you'd have to generate a thousand tables. If you had a hundred thousand users, you’d have to generate a hundred thousand tables. Doing that per-password salt gives us a little bit more computational complexity.
00:15:43.440 It takes longer for us to crack these passwords. Unfortunately, it is still a pretty good solution for 1976. This is roughly what Unix’s crypt3 does.
00:15:56.560 That was written in 1976, and at the time, a computer could calculate approximately four of these hashes per second. But today we have this—an AMD AX 7990— which costs less than a thousand bucks.
00:16:08.960 So, if you really wanted one, you could probably get one. It can compute 1.5 billion hashes a second.
00:16:20.960 So now, we’re back to being able to generate these tables so trivially that generating one table per user is actually not a problem anymore.
00:16:33.760 The reason that’s the case is that these hashing algorithms are not designed for password security; they’re actually designed typically for file integrity. They provide a way to get checksums of things so you can verify that something is the same over a network transfer.
00:16:50.160 We are just using it improperly to check that that thing, which is the same on both ends, is a password. So, we need a hashing algorithm that’s not designed to be fast like these are, so your network transfers are quicker.
00:17:04.960 We need one that’s designed to be purposefully slow. So, in 1999, Niels Provos and David Mazières published a paper about future adaptable password schemes, where they came up with bcrypt.
00:17:17.520 Now bcrypt hits all of the sweet spots that we’ve already talked about: it’s a one-way hash that’s pre-image resistant, deterministic, and has built-in per-password salts. We’ll see them in a second.
00:17:35.680 The salts are 128 bits long; that's a nice bit of extra entropy. There are also two additional goodies: one is the underlying cipher, which is xBlowfish, based on Blowfish, which is notably an expensive cipher.
00:17:49.760 The EKS stands for expensive key schedule, so it’s even more expensive to get the algorithm up and running. It takes longer to get booted and requires more memory.
00:18:01.680 More RAM kind of mitigates the problem of GPUs, which typically just provide processing power; they don't have RAM along with them. More importantly and interestingly is the notion of adaptive cost.
00:18:16.000 Let's go back to our database dump and look at it again. These are now the passwords hashed with bcrypt. Let’s investigate a bcrypt digest.
00:18:32.960 Ignore the dollar signs; they’re just delimiters and don’t mean anything. This last column, I guess you would call it, of the digest is the actual hash—that’s the checksum that comes out at the end.
00:18:47.520 It’s a 192-bit number encoded in a slightly modified base64. To the left of it is the salt, and instead of being stored in a separate database column, it’s stored right in the digest.
00:19:02.560 So, it’s more convenient, and we don’t have to worry about digest; they’re built into the algorithm. The salts on the far end are just identifiers of the algorithm we used, so this actually came out of Unix’s password schemes.
00:19:18.560 In those schemes, you could have multiple different ones used for different users and also change them over time. 2a just means this is bcrypt. There’s also 2x and 2y, which also mean this is bcrypt for historical reasons.
00:19:34.080 We can talk about them later; they’re not that interesting. But more interesting is the second column, the '10'. What does that cost mean? It means that when we hash 'Peppercorn' with bcrypt with a cost of 10, we get some output.
00:19:48.800 When we hash it again with a cost of 10, we get a different output. We already expected that because of salting. When we hash it a third time with a cost of 14, we get a third output.
00:20:05.840 This is not that interesting until you look at how long it took for each of these to happen. The first one took about 0.06 seconds; the second one also about 0.06 seconds, but the third one took more than a second.
00:20:19.920 What we can do is march forward this cost over time as computers get faster. If we start today with a cost of 12, a year from now we can use a cost of 13, and ten years from now we can use a cost of 25 to keep up with computing speed.
00:20:36.160 Here are the approximate average times it would take to do them on my computer using each of these costs. The thing that you kind of have to balance is the security of being able to have a long cost and the login speed for your users.
00:20:52.960 If you are just doing a login flow and want to increase it by four seconds, that’s kind of bad. But if you increase it by a half second, it might not be noticeable.
00:21:06.160 But if you use basic authentication for your APIs, where every single request comes with a password, then it's a half-second added to every request. You might not want that.
00:21:19.440 So, you do have to balance it for your use case. But what is good is that as computers get faster, you can increase the cost. That’s the future adaptability.
00:21:34.960 So using bcrypt with our set cost, the attack that took 87 seconds before, would now take about 84,000 years to complete. So, that’s a pretty good improvement.
00:21:51.920 Bcrypt is kind of the sweet spot for us because it has been researched for many years, was written by true cryptanalysts, is secure, and has a Ruby library, which we'll cover shortly.
00:22:02.000 Some of you are now thinking in your head, 'Why don’t you just use PBKDF2, or why don’t you use scrypt, or why don’t you use some other password hashing algorithm?' That’s fine, too! You’re probably okay.
00:22:16.480 PBKDF2 is actually the government-approved kind of password hashing scheme, so if you do any government work, I think you have to use that. They are both fine; I think they’re worse, but not significantly worse.
00:22:29.680 If you are already using one of them, you don’t have to convert over. But if you are, you’re already ahead of the class, so don’t worry about it.
00:22:43.120 How can we fix our problem now that we have all of these SHA-1 passwords? We need some way to convert them to bcrypt. If we already have plain text, it’s easy; you can just run a one-shot to do it for you in the background.
00:22:57.920 If we have only the hash, however, it’s irreversible, so we can’t encrypt it with bcrypt. The only time we can get the plain text password is by hooking into our authentication.
00:23:10.480 This is effectively a dumbed-down method of authentication: the password comes in, you use your hashing method, and you check to see if the digest matches the password coming in.
00:23:24.720 We want to get here using bcrypt to do it. The astute readers of the audience will notice the double equals up here that is seemingly comparing the plain text password to the decrypted digest.
00:23:39.680 Some of you are saying, 'I thought bcrypt was irreversible because it’s a hash.' Well, it is! Bcrypt in Ruby overrides the equals operator to make this a comparison.
00:23:52.240 I think this is one of the worst design decisions of bcrypt Ruby, but you will see it happen. If you check this in a pull review, someone will definitely point it out.
00:24:06.640 There is an alias for it that I think is called 'is_password' that you can use, but that’s a little awkward too. I keep meaning to change that, but that’s what it is.
00:24:20.280 So, the easiest way to deal with this is to throw in a pre-filter to our auth flow to convert where we have already converted. We can go through the conversion and then do the bcrypt one.
00:24:34.720 That conversion just checks if we’ve already converted, then bcrypt has a nice valid_hash method that you can use to check if it’s already done; otherwise, we have the plain text and just update it to the bcrypt one.
00:24:50.880 You can do it in the background, and that’s exactly what we did. All of this code is actually taken right out of Harvest when we did the conversion.
00:25:06.240 And these were our users with decrypted passwords over time. You can see there was a big spike initially as all the daily users and Mac app authenticated, and then it kind of trailed off over time.
00:25:20.960 But it got us most of the way there. We still had some remaining ones. That taper though, was unfortunate. But luckily, I had already extracted a bunch of plain text passwords when I attacked the database.
00:25:32.720 So, I just did it a second time, but this time, I had it convert all the passwords, and that got us the rest of the way there.
00:25:48.480 There were a couple of outliers that had actually good passwords that we couldn’t crack or that did not log in during the couple of weeks that we did this for them.
00:26:03.680 We just reset their passwords and sent them an email telling them they had to change their passwords and we received no complaints; it’s not even that scary to do.
00:26:18.960 People won’t freak out. There is one downside to bcrypt: because it’s an expensive algorithm, that means it will increase the CPU load.
00:26:32.640 Particularly as we support basic auth from our API, any API call that’s coming in with a password has to go through the bcrypt overhead.
00:26:48.960 We saw roughly a doubling of our CPU load, but it’s definitely within the realm of acceptability, and the trade-off for the security we got from it was totally worth it.
00:27:01.680 So, just be aware of it, but it’s not that bad. Act one was just the exposition; that’s the boring part. You can learn all of that on your own.
00:27:14.960 Act two is where we add conflict in a three-act play, so we’re going to talk about fat binary gems.
00:27:27.920 As I mentioned earlier, bcrypt has a Ruby library called 'bcrypt-ruby.' You can find it on GitHub at Coda Hale’s bcrypt-ruby.
00:27:43.440 While doing this, I wanted to add a feature to bcrypt-ruby. But when I tried to do that, the tests didn’t run, the dependencies were out of date, and there were missing docs.
00:27:56.760 So, my one pull request turned into a dozen pull requests. If you do that long enough, eventually someone will just say, 'Can you please give this person commit bit?' And then suddenly, I was the maintainer of bcrypt-ruby.
00:28:09.600 There have been three de facto maintainers: Coda Hale is the third one; he wrote it initially, then TenderLove took over, then TMM-1 amongst Gupta took over from GitHub, and now it’s me.
00:28:26.240 That number of 5.8 million is now like 12 million downloads, which is terrifying, but so it goes! Anyway, this is what bcrypt-ruby looks like.
00:28:39.440 But more accurately, this is what bcrypt-ruby looks like. bcrypt-ruby is just a wrapper around C and Java extensions, which is why it’s not natively implemented in Ruby.
00:28:56.480 Ruby is not slow it has been debunked, but it is definitely slower, and your attacker is going to use the fastest thing they have. Your attacker will use a C implementation.
00:29:12.720 Therefore, you don’t want to have unnecessary overhead and lower your costs to make it more speed efficient when your attacker is going to have the advantage.
00:29:25.760 So, it uses the C and Java extensions, which means that when you distribute a gem, you have to distribute it with compiled binaries for the sake of your users.
00:29:38.560 You can see the 315 actually has four versions. The third one’s a native one; the fourth one is the Java version, and the top two are Windows fat binaries.
00:29:54.960 What they are is gems built with support for multiple versions of Ruby—because that’s how Windows plays. However, I’m not a Windows developer so I don’t know much about that.
00:30:07.440 Luckily, when Aman added this to bcrypt-ruby, he wrote this awesome commit message with all these instructions, but he wrote it three years ago.
00:30:23.520 Like anything on the Internet written about computers, it’s three years old; it doesn’t work. Aaron on his blog actually introduced the notion of fat binary gems five years ago.
00:30:36.160 He made the same meme as me five years before me, but anything written about computers on the internet that's five years old definitely doesn’t work.
00:30:49.120 Ultimately, all of this is just wrapping up rake-compiler, which is this library that uses the power of rake to help you cross-compile your gems, so that you can provide these binaries to all these different platforms.
00:31:00.160 However, nice long documentation with all of these instructions—none of that works.
00:31:13.280 The Rails team has this thing that I think is great called the Rails Dev Box, and what it is is a virtual machine that has all of these external dependencies.
00:31:26.640 This means that you are not required to have them on your local machine, such as all of the databases, and the system dependencies for running them.
00:31:39.440 That's very useful so you can run the tests on your local machine without having every possible environment set up. I had a dream to create a rake-compiler dev box that had all the Ruby versions I need.
00:31:52.480 It should have the GCC, JDK, mingw, which is for compiling Windows binaries on UNIX-like machines. Vagrant exists and provides configurable lightweight reproducible portable developer environments.
00:32:05.920 So, I set up a Vagrant box that had everything I needed to compile these binaries. None of that worked.
00:32:18.080 Difficulties can be overcome sometimes, but for now it still is a challenge. This is where I opened up rake-compiler issue number 79.
00:32:31.360 I effectively said I followed all of the documentation as long as possible. I tried to do it in the cleanest environment I could, and nothing worked.
00:32:44.800 In our three-act play, this would be the climax! This is Luis Lavena.
00:32:58.240 Luis is the developer of the One-Click Ruby Installer for Windows. By working on all of this stuff for Ruby on Windows, he is also a member of the Ruby Core Team.
00:33:11.680 By virtue of both of these things, he was voted a Ruby hero in 2010. More importantly, he is the developer of rake-compiler.
00:33:22.560 After I opened up that issue on rake-compiler, he opened up rake-compiler dev box issue/pull request number two.
00:33:33.680 He dropped on me triple hearts—not once, not twice, not three times, but four times! But here’s the problem.
00:33:47.680 This was a great pull request and everything, but I’m twelve hearts in the hole. I need you guys to help me!
00:34:02.480 Please pull out your devices and tweet at Luis right now three hearts. Additionally, if you are on a Mac—on Mavericks or later—hit control + command + space to get all the fancy emoji!
00:34:15.520 So go to town on Luis! I’ll wait. Thank him for being a great OSS contributor and maintainer. He truly is the best.
00:34:29.680 While you’re doing that to half of you, I want to encourage you to find your Luis. Thank the person that has helped you to do things that are often too hard for you to figure out on your own.
00:34:43.520 But more importantly, cooperate with them. Thinking is easy, but actually collaborating can be a lot of fun and very rewarding.
00:34:55.680 Luis lives in Argentina and Paris, splitting his time between them. It’s nice to see global collaboration.
00:35:07.680 To the other half of you who are already maintaining giant libraries or are already a mentor of some way, I encourage you to be the Luis you wish to see in the world.
00:35:22.480 While it’s easy to get frustrated when someone comes in with the same issue you’ve seen a hundred times, consider that the problem might be the documentation.
00:35:35.760 Rewrite your docs to be more friendly to people, or just be supportive of them when they open up usage issues.
00:35:49.040 I know a lot of people don’t like GitHub for usage support, but you can be friendly to people. So, what have we learned today?
00:36:02.560 Number one: just use bcrypt. If you're not already doing it, you should!
00:36:14.560 Come find me afterward; we’ll cry, we’ll hug, and we’ll convert our passwords. Number two: distribute a dev box.
00:36:29.760 If you have any kind of complicated library you’re shipping, make it easier for others to run it by distributing a dev box.
00:36:42.080 Alternatively, if you make or maintain a gem that has extensions, try rake-compiler devbox; it’ll make your life a lot easier.
00:36:57.680 Most importantly, I want to encourage you to release, collaborate, and iterate. With that, I’m TJ Schuck. Thank you!
00:37:18.320 I have 52 seconds for questions. How far will that adaptive cost value scale? Was the question? Potentially endlessly.
00:37:31.040 It's just an integer that you pass in. So, as time marches on you could raise that cost to a hundred or a thousand. Something tells me that will no longer be our problem.
00:37:45.760 In our lifetimes, we might hit 20, but even still, it operates adding up the cost factor in exponents.
00:38:00.560 Also, like Moore's Law, computers are keeping up. Does anyone have anything else?
00:38:11.040 Yes.
00:38:24.800 Did we have any min or max values on the password field in our database? Yes, now we do.
00:38:37.440 But Harvest is actually a decently old Rails app; it was written before Rails 1.0. I think it launched in 2006, when we were all terrible at the Internet.
00:38:50.560 So, I think our password restrictions were much looser then, and as time has gone on they’ve gotten stricter.
00:39:00.960 But legacy users have had worse passwords. Today, if you have a Harvest account, you have a more secure password, which is required to be longer and have a little more complexity.
00:39:14.560 But as we saw, that doesn’t necessarily help. So, I encourage users to utilize a password manager like OnePassword or LastPass.
00:39:27.040 But yeah, now we have stricter requirements; it has just been a gradual evolution.
00:39:40.320 What were the passwords I couldn't crack? By definition, no.
00:39:57.840 Looking at that list, there was nothing that was like a 30-character long random string. There were some passwords that were like passphrases like the XKCD comic you’ve seen.
00:40:10.080 That XKCD comic is partly true in a strictly computational sense, but again, these word lists have gotten better. Many tools will combine words in different orders.
00:40:24.160 So, I recommend actually using random passwords. Length is also good, but there was nothing that wasn't expected.
00:40:34.160 Yes.
00:40:46.080 So, the question was about Devise. Many people use Devise. It uses bcrypt; I believe it uses a default cost of 10.
00:40:58.880 But that might be a little low. I think we're at 12 but again it depends on your use case. You can easily set the cost externally.
00:41:12.160 So that Devise can just use that cost under the hood. Also related to Devise is secure password, which is in Rails’ Active Support.
00:41:23.920 It is kind of like a minimal implementation that uses bcrypt. So, if you use either has_secure_password or Devise, you're set.
00:41:35.440 Yes.
00:41:49.520 The question was do I know anyone implementing a gem for two-factor authentication? I don’t offhand.
00:42:01.920 But I wouldn’t be surprised if there’s one; I just don’t know. If you do have a question but you’re too shy to ask, you can find me afterward. I’ll be around. Thank you!