Oh, the Secrets You’ll Know

Beware of [hash]CatOh, the secrets you’ll know if to GitHub you go. The phrases committed by coders exhibited a mistaken sense of security.

A password ensures, while its secrecy endures, a measure of proven identity.

Share that short phrase for the public to gaze at repositories open and clear. Then don’t be surprised at the attacker disguised with the secrets you thought were unknown.


It’s no secret that I gave a BlackHat presentation a few weeks ago. It’s no secret that the CSRF countermeasure we proposed avoids nonces, random numbers, and secrets. It’s no secret that GitHub is a repository of secrets.

And that’s how I got side-tracked for two days hunting secrets on GitHub when I should have been working on slides.

Your Secret

Security that relies on secrets (like passwords) fundamentally relies on the preservation of that secret. There’s no hidden wisdom behind that truism, no subtle paradox to grant it the standing of a koan. It’s a simple statement too often ignored, bent, and otherwise abused.

It started with research on examples of CSRF token implementations. But the hunt soon diverged from queries for connect.sid to tokens like OAUTH_CONSUMER_SECRET, to ssh:// and mongodb:// schemes. Such beasts of the wild had been noticed before; they tend to roam with little hindrance.

connect.sid extension:js

Sometimes these beasts leap from cover into the territory of plaintext. Sometimes they remain camouflaged behind hashes and ciphers. Crypto functions conceal the nature of a beast, but the patient hunter will be able to discover it given time.

The mechanisms used to protect secrets, such as encryption and hash functions, are intended to maximize an attacker’s effort at trying to reverse-engineer the secret. The choice of hash function has no appreciable effect on a dictionary-based brute force attack (at least not until your dictionary or a hybrid-based approach reaches the size of the target keyspace). In the long run of an exhaustive brute force search, a “bigger” hash like SHA-512 would take longer than SHA-256 or MD5. But that’s not the smart way to increase the attacker’s work factor.

Iterated hashing techniques are more effective at increasing the attacker’s work factor. Such techniques have a tunable property that may be adjusted with regard to the expected cracking speeds of an attacker. For example, in the PBKDF2 algorithm, both the HMAC algorithm and number of rounds can be changed, so an HMAC-SHA1 could be replaced by HMAC-SHA256 and 1,000 rounds could be increased to 10,000. (The changes would not be compatible with each other, so you would still need a migration plan when moving from one setting to another.)

Of course, the choice of work factor must be balanced with a value you’re willing to encumber the site with. The number of “nonce” events for something like CSRF is far more frequent than the number of “hash” events for authentication. For example, a user may authenticate once in a one-hour period, but visit dozens of pages during that same time.

Our Secret

But none of that matters if you’re relying on a secret that’s easy to guess, like default passwords. And it doesn’t matter if you’ve chosen a nice, long passphrase that doesn’t appear in any dictionary if you’ve checked that password into a public source code repository.

In honor of the password cracking chapter of the upcoming AHT 4th Edition, we’ll briefly cover how to guess HMAC values.

We’ll use the Connect JavaScript library for Node.js as a target for this guesswork. It contains a CSRF countermeasure that relies on nonces generated via an HMAC. This doesn’t mean Connect.js implements the HMAC algorithm incorrectly or contains a design error; it just means that the security of an HMAC relies on the secrecy of its password. Developers should know this.

Here’s a snippet of the Connect.js code in action. Note the default secret, ‘keyboard cat’.

var app = connect()
  .use(connect.session({ secret: 'keyboard cat' }))

If you come across a web app that sets a connect.sess or connect.sid cookie, then it’s likely to have been created by this library. And it’s just as likely to be using a bad password for the HMAC. Let’s put that to the test with the following cookies.

Set-Cookie: connect.sess=s%3AGY4Xp1AWB5PVzYHCANaXHznO.PUvao3Y6%2FXxLAG%2Bp4xQEBAcbqMCJPACQUvS2WCfsmKU; Path=/; Expires=Fri, 28 Jun 2013 23:13:52 GMT; HttpOnly
Set-Cookie: connect.sid=s%3ATdF%2FriiKHfdilCTc4W5uAAhy.qTtH9ZL5pxgClGbZ0I0E3efJTrdC0jia6YxFh3cWKrU; path=/; expires=Fri, 28 Jun 2013 22:51:58 GMT; httpOnly
Set-Cookie: connect.sid=CJVZnS56R6NY8kenBhhIOq0h.0opeJzAPZ3efz0dw5YJrGqVv4Fi%2BWVIThEsGHMRqDw0; Path=/; HttpOnly

Everyone’s Secret

John the Ripper is a venerable password guessing tool with ancient roots in the security community. Its rule-based guessing techniques and speed make it a powerful tool for cracking passwords. In this case, we’re just interested in its ability to target the HMAC-SHA256 algorithm.

First, we need to reformat the cookies into a string that John recognizes. For these cookies, resolve the percent-encoded characters, replace the dot (.) with a hash (#). (Some of the cookies contained a JSON-encoded version of the session value, others contained only the session value.)


Next, we unleash John against it. The first step might use a dictionary, such as a words.txt file you might have laying around. (The book covers more techniques and clever use of rules to target password patterns. John’s own documentation can also get you started.)
$ ./john --format=hmac-sha256 --wordlist=words.txt sids.john

Review your successes with the --show option.
$ ./john --show sids.john

Hashcat is another password guessing tool. It takes advantage of GPU processors to emphasize rate of guesses. It requires a slightly different format for the HMAC-256 input file. The order of the password and salt is reversed from John, and it requires a colon separator.


Hashcat uses numeric references to the algorithms it supports. The following command runs a dictionary attack against hash algorithm 1450, which is HMAC-SHA256.
$ ./hashcat-cli64.app -a 0 -m 1450 sids.hashcat words.txt

Review your successes with the --show option.
$ ./hashcat-cli64.app --show -a 0 -m 1450 sids.hashcat words.txt

Hold on! There’s movement in the brush. Let me check what beastie lurks there. I’ll be right back…

Password Interlude in D Minor

While at least one previous post here castigated poor password security, a few others have tried to approach the problem in a more constructive manner. Each of these posts share fundamental themes:

  • Protect the password in transit from the threat of sniffers or intermediation attacks — Use HTTPS during the entire authentication process. HSTS is better. HSTS plus DNSSEC is best.
  • Protect the password in storage to impede the threat of brute force guessing — Never store the plaintext version of the password. Store the salted hash, preferably with PBKDF2. Where possible, hash the password in the browser to further limit the plaintext version’s exposure and minimize developers’ temptation or expectation to work with plaintext. Hashing affects the amount of effort an attacker must expend to obtain the original plaintext password, but it offers little protection for weak passwords. Passwords like p@ssw3rd or lettheright1in are going to be guessed quickly.
  • Protect the password storage from the threat of theft — Balance the attention to hashing passwords with attention to preventing them from being stolen in the first place. This includes (what should be) obvious steps like fixing SQL injection as well as avoiding surprises from areas like logging (such as the login page requests, failed logins), auditing (where password “strength” is checked on the server), and ancillary storage like backups or QA environments.

Implementing PBKDF2 for password protection requires two choices: an HMAC function and number of iterations. For example, WPA2 uses SHA-1 for the HMAC and 4,096 iterations. A review of Apple’s OS X FileVault 2 (used for full disk encryption) reveals that it relies in part on at least 41,000 iterations of SHA-256. RFC 3962 provides some insight, via example, of how to select an iteration count. It’s a trade-off between inducing overhead on the authentication system (authentication still needs to be low-latency from the user’s perspective, and too much time exposes it to easy DoS) versus increasing an attacker’s work effort.

A more sophisticated approach that I haven’t covered yet is the Secure Remote Password (SRP) protocol. SRP introduces a mechanism for password authentication and key exchange; becoming a more secure way to protect the authentication process from passive (e.g. sniffing) and active (e.g. replay, spoofing) attacks. However, the nature of browser security, especially the idea of crypto implemented in JavaScript, adds some interesting wrinkles to the practical security of SRP — not enough to dismiss SRP, just to understand how DNS, mixed-content, and JavaScript’s execution environment may have adverse effects. That’s a topic for another day.

Finally, sites may choose to avoid password management altogether by adopting strategies like OAuth or OpenID. Taking this route doesn’t magically make password-related security problems disappear. Rather than specifically protecting passwords, a site must protect authentication and authorization tokens; it’s still necessary to enforce HTTPS and follow secure programming principles. However, the dangers of direct compromise of a user’s password are greatly reduced.

The state of password security is a sad subject. Like D minor, which is the saddest of all keys.

LinkedIn, HashedOut

Linked-“Be great at what you do”-In, bringing you modern social networking with worse password protection than 1970s UNIX. Not only did LinkedIn avoid a robust, well-known password hashing scheme like PBKDF2, they didn’t even salt the passwords. Something FreeBSD programmers have been doing for years.

It also appears some users are confused as to what constitutes a good password. Length? Characters? Punctuation? Phrases? An unbelievable number of users went for length, but couldn’t be bothered hitting the shift key, space bar, or one of those numbers above qwerty. I sat down for 20 minutes with shasum and grep — and my bookshelf for inspiration — to hand-hack some possible passwords.

grep `echo -n myownpassword | shasum | cut -c6-40` SHA1.txt

The grep/shasum trick works on Unix-like command lines. John the Ripper is the usual tool for password cracking without entering the super assembly of GPU customization. And if someone tells you to use node.js instead of Perl, Python, Ruby, or that grep command because a non-blocking IO is faster…just walk away. Walk. Away. Your brain will thank you.

Anyway, I love sci-fi and fantasy as much as the next person. I still run an RPG on a weekly basis; there’s no dust on my polyhedrals. Speaking of RPGs. I started the guesswork with 1st Edition AD&D terms only to strike out after a dozen tries, but your 2nd edition references aren’t bad:

waterdeep — Under Mountain was awesome, unlike your password.

menzoberranzan — Yeah, mister dual-scimitars shows up in the list, too. This single-handedly killed the Ranger class for me. (Er, not before I had about three Rangers with dual longswords; ’cause that was totally different…)

No one seems to have taken “1stEditionAD&D”. Maybe that’ll be my new password. 14 characters, a number, a symbol, what’s not to love? Aside from retroactive revelation?

tardis — Come on, that’s not even eight characters. Would tombaker or jonpertwee approve? I don’t think so. But no Wiliam Hartnell? Have you no sense of history? Even for a timelord?

doctorwho — Longer, but…um…we just covered this.

badwolf — Cool, some Jack Harkness fans out there, but still not eight characters.

torchwood — Love the show, but your anagram improves nothing.

kar120c — I’m glad there’s a Prisoner fan out there. It was a cool series with a mind-blowingly bizarre, pontificating, intriguing ending that demands discussion. However, not only is that password short, it even shows up in my book (upcoming edition, too). I should find out who it was and send them a signed copy.

itsatrap — Seriously? You chose a cliched, meme-inducing movie quote that short? And you couldn’t be bothered with an exclamation point at the end? At least you chose a line from the best of the three movies. (No, the last three aren’t worth considering. And, yes, they’re the “last” three because it’s only an “e” away from “least.”)

myprecious — Not anymore.

onering — Onering? While you were out onering your oner a password cracker was cracking your comprehension of LotR. By the way, hackers have also read earthsea, theshining and darktower. Hey, they’ve got good taste.

I adore the Dune books. Dune is in the top list of my favorite books. Just this week I offered a nice quote from the Bene Gesserit. Seems I’m not the only fan:

benegesserit — Don’t they have some other quotes? Something about fear?

fearisthemindkiller — Heh, even the hackers hadn’t cracked that one yet. Referencing The Litany Against Fear would have been a nice move except that if “fear is the mind killer” then “obvious is the password.”

entersandman, blackened, dyerseve — What are you going to do when you run out of Metallica tracks? Use megadeath? It’s almost sadbuttrue. And jethrotull beat them at the Grammy’s. So, there.

loveiskind — Love is patient, love is kind, hackers aren’t stupid, passwords they find.

h4xx0r — No, you’re not.

notmypassword — Actually, it is. At least you didn’t choose a 14-character secretpassword. That would just be dumb.

stevejobs — Now how is he going to change his password?

Comments on this post are only open to users with strong passwords. Please place your password at the beginning of the comment so we know you didn’t choose something as pop-culturally obvious that I can figure it out in 20 minutes.

So You Want to Hash a Password…

Congratulations. You’re thinking about protecting a password; a concept that well-known1 sites, to this day2, fail3 to comprehend.

Choose an established, vetted algorithm (SHA-256 would suffice), include a salt (we’ll explain this a bit later), hash the password. Get rid of the plaintext password. Done. See how simple that was? There’s even Open Source code4 to help you with more complex issues.

But once you’ve set foot on the path of hashing passwords you might be tempted to make the hash Even Better. An apparently common idea is that if you hash a password once, hashing it twice makes it more secure. Being “more secure” is a commendable goal, but beware the wild beasts of cryptography, for they are subtle and quick to…well, you should be able to finish that thought.5

Repeating encryption or hashing algorithm isn’t a bad idea, it’s just not fully thought-through idea. First, we need a paragraph or three to catch everyone up on hashing and brute force attacks:

A cryptographic hash function takes an arbitrary-length input and produces a fixed-length output that has no statistical relation to the input. Consequently, a password like friend becomes an unintelligible string like 97823jnsndf234.6 An important property of a cryptographic hash function is that it’s irreversible (information is lost, similar to a lossy compression algorithm). No algorithm exists to turn the output 97823jnsndf234 back into friend. Alternately, an encryption function turns friend into mellon and if you know the encryption scheme and a key, then you know how to turn mellon back into friend. AES is an example of an encryption function.

Cracking a hashed password requires effort on the part of the attacker. This effort, or work factor, represents the time to execute a single hash function multiplied by the expected number of guesses required to find the correct input to the hash function. For example, an attacker might try all six-letter strings such as friena, frienb, frienc until finally hashing the guess of friend and observing that the output matches the reference hash, 97823jnsndf234.

Trying all six-letter lowercase combinations of the English alphabet requires 308,915,776 guesses (26 characters to the 6th power). This is actually a relatively small number in the age of multi-core behemoths and GPU trickery. If a single hash function takes 1 microsecond to execute on a particular system, then the complete brute force will take about 5 minutes. If you pass each input through the hash function N times, then you increase the work factor by N. With N = 100 the six-character attack would take close to 9 hours. The attacker is going to get the password eventually, but now it will take N times longer.

Notice that the previous equation only cared about the time required to execute a single hash function. From this perspective it doesn’t matter if the hash algorithm produces a 128 bit or 512 bit output. It only matters how long it takes to obtain the output. (We’re only talking about hashing and repeated hashing here; bit lengths and algorithm selection still have important security implications for other reasons and against other attacks.)

Here is a simplified explanation of how a repeated hash function fails to universally improve the work factor to brute force a value. The input plaintexts are marked P (with Greek letter subscripts). This brief examples uses 10 iterations of a lossy hash function. The output of each intermediate hash is marked H with a numeric subscript. The final hash iteration is marked C with a subscript corresponding to the original plaintext.

The following line shows how the final value for an input plaintext is achieved:

Pα -> H1 -> H2 -> H3 -> H4 -> H5 -> H6 -> H7 -> H8 -> H9 -> Cα

A different input should produce a different final value:

Pβ -> H43 -> H44 -> H45 -> H46 -> H47 -> H48 -> H49 -> Cβ

A problem occurs when the original plaintext has a collision with one of the intermediate or final hash values. For example, what if Pγ and H7 have the same result when passed into the hash function? You have an overlapping sequence from the end of Pα’s chain:

Pγ -> H8 -> H9 -> H10 -> H11 -> H12 -> H13 -> H14 -> H15 -> H16 -> Cγ

A more pathological case happens when a sequence overlaps significantly:

Pδ -> H44 -> H45 -> H46 -> H47 -> H48 -> H49 -> H50 -> Cδ

The way an attacker would exploit these artifacts is by creating some chain reference tables, much like a rainbow table. Yet in this case, the chain reference is used to skip rounds. For example, given an input plaintext Px, if the first hash round is H13 and the table has a precomputed chain with an H13 in it, then the attacker can fast-forward 10 steps (or however many steps have been precomputed) to get the Cx.

This case for this Time-Memory-Trade-Off (TMTO) attack chains didn’t present any math or probability calculations to back up these assertions. If you’re about to dismisse this attack based on the lack of hard evidence (in this article), consider something else about repeated rounds: they do not introduce additional entropy. Consequently, each round might actually weaken the entropy of the initial input despite the increased work factor due to additional rounds. In a worst case scenario, this dilution of entropy might lead to collisions that make a brute force search even easier.

Repeated hashing does not increase entropy (the “difficulty” of the initial password), it only increases the work factor. Repeated hashing of iloveyou doesn’t make the password any harder to guess, just longer to get there.

Think of it in terms of the attacker’s dictionary. The attacker has a pre-defined list of common passwords, from iloveyou to KAR120C. Neither the hashing algorithm nor the number of repetitions has any impact on this dictionary. Those only affect the amount of time required for the attacker to cycle through the dictionary.

The common theme for using cryptosystems is to first look for implementations that conform to a standard7 rather than creating something you think is new, novel, and unique.

In the case of repeated encryption, you should turn to RFC 2898 for the Password-Based Key Derivation Function 2 (PBKDF2).8 PBKDF2 inserts an iteration counter to prevent “chain” attacks. In other words, the attacker must perform every encryption stage. At a minimum, the iteration prevents the attacker from shortcutting rounds using a TMTO trick.

Where repeated rounds increase the attacker’s work factor, salts defeat other precomputation (a.k.a Rainbow table) attacks. A salt is merely a number of bytes (like a string, though it need not be) prefixed or suffixed to a password.

Salting passwords affects the composition of the attacker’s dictionary. Rather than trying the password me+galadriel the attacker must include a salt, which makes it somethinglongbefore-me+galadriel. Salts don’t make the dictionary bigger, they make the dictionary specific to the salt. The idea here is that all of the effort put forth to crack a password with a particular salt cannot be reused to crack the same password with a different salt — the brute force must begin anew. The hash for somethinglongbefore-me+galadriel is completely different from anotherstringinfrontof-me+galadriel. This is the primary way to prevent another TMTO attack, usually referred to as a rainbow table.

If you want a recommendation on the length of a salt, 19 is a nice, mystical number.9

Every measure you take to encrypt and obfuscate the password reduces the risk should the web site’s password store be stolen. (There’s quite a bit of precedent for such things.)

However, everything you do to protect the password in the database (or wherever it is stored) has no bearing on a multitude of other attack vectors, including the database itself.

Imagine a SQL injection attack that sets every user’s password to the hash of a password known to the attacker. What would you rather do? Download the entire DB over a period of several minutes or change every account to a password you know? These approaches have different goals: obtaining original passwords are likely re-used across email, banking, and other sites whereas setting a known password gives immediate access to the site at the expense of blatant activity more likely to be noticed.

Imagine a scenario where the attacker is able to modify the login page so cleartext passwords are stored to a file or shuffled off to another web site.

The focus on encrypting the password and preserving its confidentiality is laudable. However, too much focus takes away from the more immediate threat of brute forcing the login form itself. The work factor to crack a short password like ncc1701 might be measured in days or weeks depending on the method of encryption. On the other hand, the attacker may have a list of the site’s users (or have a reliable way of generating likely user names). In this scenario, the attacker targets the login page with a static password (ncc1701) and cycles through the user list.

Once again, there’s precedent of success for this approach such as against our high-profile friend Twitter. In 2009 a hacker cracked the long (more than the mystical “8 character minimum”), but unsophisticated password happiness for an account that had permissions to reset passwords for any other account.10

Clearly, it didn’t matter how well happiness had been kept secret, encrypted, obfuscated, and otherwise concealed. There were no limits on how many times the login page could be requested for brute forcing the account. Furthermore, the password protection for every other account was moot since the hacker now had access to an admin account from which he could take over any other. The only apparent good news in this scenario is that, while several accounts were compromised, the original passwords to those accounts were not. This is possibly negligible consolation, but important none the less considering the prevalence of password re-use across web sites.

By all means, put some effort into hashing passwords using well-established techniques. You’ll be adding to the work factor of anyone trying to crack the passwords should the password store ever be extracted from the site.

On the other hand, you may be increasing your own work factor with over-engineered solutions for password protection at the expense of other protections — like preventing SQL injection or rate limiting authentication points.

Here’s an additional note I made in the comments, but should highlight in the article:

For comparison, WPA2 uses PBKDF2 with the SSID of the network as a salt, a 256-bit key, HMAC-SHA1 for the algorithm, and 4096 iterations.

If you trying to figure out “what’s best” for hashing a password, consider WPA2 as the reference metric. For example, your hashing should generate a work factor of N times the work factor for WPA2 where N is your degree of paranoia that WPA2 is easily broken.

If you chose a double-digit N “just because”, then why would you ever use a wireless network (phone or Wi-Fi, GSM A5/3 or WPA2, etc.)? It’s much more likely someone will be able to sniff your encrypted traffic than they’ll ever get your hashed passwords. In fact, GSM’s A5/X algorithms have reported attacks. Seems like another reason to layer encryption, such as always using HTTPS.

For another comparison, the OSX File Vault apparently uses PBKDF2 with 1000 iterations. (Although it’d be nice to have a more detailed reference.)


1 http://risky.biz/sosasta
2 http://blogs.wsj.com/digits/2011/06/08/some-top-apps-put-data-at-risk/
3 http://www.pcworld.com/article/229316/lulz_boat_hacks_sonys_harbor_faq.html#tk.hp_fv
4 http://www.keyczar.org/
5 If you’re not well-read in crypto you should at least be well read in fiction. After all, the security of a home-grown cryptosystem is closer to fiction.
6 It’s not necessary to think of any specific hash function at this point, but if you want a more concrete example, “friend” is hashed to the hexadecimal string “8e8b4d64f704c7a6aa632a7e6c2024e4f9fed79caac319e6bb7754db587e6f58” using the SHA-256 algorithm.
7 http://csrc.nist.gov/groups/ST/hash/index.html
8 http://www.ietf.org/rfc/rfc2898.txt
9 Read the Dark Tower series by Stephen King, books V and VII in particular. The series also has one of the greatest first lines in a book, “The man in black fled across the desert, and the gunslinger followed.”
10 http://www.wired.com/threatlevel/2009/01/professed-twitt/

The alien concept of password security

A post on Stack Overflow1 seeks advice on the relative security between implementing a password reset mechanism that emails a temporary link vs. one that emails a temporary password. The question brings to mind some issues addressed in Chapter 5: Breaking Authentication Schemes of The Book. Stack Overflow questions typically attract high quality answers, which is a testament to the site’s knowledgeable readership and reputation system. Responses to this particular post didn’t fail.

Rather than retread the answers, let’s consider the underlying implication behind the question: it can be acceptable to send passwords via email.

Don’t do it. Don’t give users the expectation that passwords might be sent via email. Doing so is unnecessary and establishes a dangerous practice as possibly acceptable. If the site ever sends a password to a user, then the user might be conditioned to communicate in the other direction. An email purportedly from the site’s administrators might ask for the user’s password to “verify the account is active”, “prevent the account from being terminated”, or “restore information”. The email need not ask for a direct response. It may be an indirect prompt for the password using cautionary, concerned language that never the less sends the victim to a spoofed login page.

Site administrators will not elicit passwords via email or any other means. Sites won’t ask for passwords except at authentication barriers. Sites shouldn’t send passwords — however temporary they may be.

“Newt. My name’s Newt.”

Passwords — shared secrets ostensibly known only to the user and the web site — are a necessary evil of authentication. The password proves a user’s identity to a web site under the assumption that only the person who logs in as Newt, for example, knows the corresponding password to the account is rebecca.

A password’s importance to web security has a frustratingly indirect relationship to the amount of control a site is able to exert over its protection. Users must be trusted not only to use hard-to-guess words or phrases, but must be trusted not to share the password or otherwise actively divulge it through accident or ignorance. Only the luckiest of potential victims will click an emailed link and be brought to a friendly page:

“That’s it man, game over man, game over!”

Password reuse among sites poses another serious risk. The theft of a user’s credentials (email address and password) for a site like http://www.downloadwarez.free might seen relatively innocuous, but what if they’re the same credentials used for allof.my.friends or http://www.mostly.secure.bank? Even worse, what if the password matches the one for the Gmail, Hotmail, or Yahoo account? In that case: Nuke the entire site from orbit. It’s the only way to be sure.”

“Seventeen days? Hey man, I don’t wanna rain on your parade, but we’re not gonna last seventeen hours!”

Use random, temporary links for password reset mechanisms via email. By this point you should be sufficiently warned off of the alternative of emailing temporary passwords. An obstinate few might choose to stick with passwords, arguing that there’s no difference between the two once they hit the unencrypted realm of email.

Instead, use a forward-thinking solution that tries to secure the entire reset process:

  • Maintain the original password until the user changes it. Perhaps they’ll remember it anyway. This also prevent a mini-denial of service where attackers force users to change their passwords.
  • Use a strong pseudo-random number generator to minimize the chance of success of brute force attacks guessing the link.
  • Expire the link after a short period of time, perhaps in minutes or hours. This narrows the window of opportunity for brute force attacks that attempt to guess links. It’s no good to let an attacker initiate a password reset on a Friday evening and have a complete weekend to brute force links until the victim notices the e-mail on a Monday morning.

“Maybe we got ’em demoralized.”

For those of you out there who visit web sites rather than create them there’s one rule you should never ignore. If the site’s password recovery mechanism emails you the original password for your account, then stop using the site. Period. Full stop. Should you be forced to use the site under threat of violence or peer pressure, whichever is worse, at the very least choose a password that isn’t shared with any other account. Storing unencrypted passwords is lazy, bad security design, and a liability.

1 Huzzah! A site name that doesn’t succumb to stripping spaces, prefixing an ‘e’ or ‘i’, or using some vapid, made-up word only because it consists of four or five letters!
2 Quotes from the movie Aliens. If you didn’t already know that stop reading and go watch it now. We’ll wait. See you in about two hours.