How to continuously keep the number of bcrypt rounds relevant to the current year's hardware?

后端 未结 3 1217
星月不相逢
星月不相逢 2021-01-12 02:08

I saw a recommendation that the number of rounds be set to ($currentYear - 2000) to account for Moore\'s law, so that 2013 would be 13 rounds and t

3条回答
  •  傲寒
    傲寒 (楼主)
    2021-01-12 02:39

    First off, I question that recommendation (adjusting cost based on year). The cost should be based on how fast your hardware is, not the current date. If you don't upgrade your server between now and 2015, there's no reason to increase the cost. All you do is slow an already slow process.

    With that said, I also question the recommendation of 1 second for most usages. If you're dealing with highly sensitive information, 1 second (or perhaps longer) is ok. But for the average website, I typically recommend between 0.25 and 0.5 seconds. In some cases you can go lower, but I wouldn't without strong justification.

    Now, to the question itself. When you use crypt() or password_hash(), the iteration count is stored in the return hash format. In fact, the salt is as well. So all information needed to compute the hash is included in it!

    And if you're not using either of those API's (or the polyfill that I maintain: password-compat), then I really have to wonder why you aren't. Don't invent your own password crypto. Don't use libraries that use native hashes (like phpass) unless you have a strong reason to (for certain governmental compliance reasons, or compatibility with PHP <= 5.2).

    It is generally considered that bcrypt is the strongest hash format today. SCrypt is stronger, but there are some issues with it, and it is still very new (and it's not available in PHP core yet). So just use bcrypt...

    The password_hash() api has a mechanism for you to do what you're asking: password_needs_rehash(). Basically, you pass in the hash, and the options you use today, and it tells you if you need to rehash it:

    if (password_verify($password, $hash)) {
        if (password_needs_rehash($hash, PASSWORD_BCRYPT, ['cost' => 14])) {
            $hash = password_hash($password);
            update_password_in_database($hash);
        }
        $loggedin = true;
    }
    

    Read the RFC for password_hash() for more information about it (I collected data from a large number of sources, and included references in the RFC).

    Edit - Follow up to @AnotherParker's Comment:

    Criminals don't stop upgrading their crackingboxes just because you didn't upgrade your server. You do need to increase the work parameter over time to thwart offline attacks.

    Sort-of true. Well, true, but misses the point of what I was talking about above.

    The cost parameter of the hash function is a time-effort tradeoff. You trade-off some time to add additional effort to each hash. On the same hardware, taking more time will yield more work. The other way to yield more work is to get faster hardware.

    But the recommendation is to test the hash function on your current hardware, and make it as expensive as you can reasonably make it. If 0.5 seconds is the maximum that you can afford today, unless you upgrade your server hardware, how is increasing the cost going to help you? In short, it won't because you'll break the maximum time limit you've already determined is important.

    So you can't increase the work parameter without also increasing the server's capabilities, unless you already were producing weak hashes.

    Also, check out this answer on the subject

提交回复
热议问题