RFC: Increasing the default BCrypt cost

php.internals

Tim Düsterhus

2 years ago
Hi in response to the recent "PASSWORD_DEFAULT value" thread [1], I've created an RFC to discuss an increase of the default BCrypt costs for `password_hash()` from the current value of 10. https://wiki.php.net/rfc/bcrypt_cost_2023 This message is intended to officially open the discussion period for that RFC. Best regards Tim Düsterhus [1] https://externals.io/message/120993

Niels Dossche

2 years ago
Hi Tim On 07/09/2023 19:26, Tim Düsterhus wrote:
> Hi > > in response to the recent "PASSWORD_DEFAULT value" thread [1], I've created an RFC to discuss an increase of the default BCrypt costs for `password_hash()` from the current value of 10. > > https://wiki.php.net/rfc/bcrypt_cost_2023
These are the kind of things that are easily forgotten. Thank you for taking care of this! I just noticed one small detail. From the RFC text: "All tests were carried out using wall-power." I guess you mean wall-time?
> > This message is intended to officially open the discussion period for that RFC. > > Best regards > Tim Düsterhus > > [1] https://externals.io/message/120993 >
Kind regards Niels

Tim Düsterhus

2 years ago
Hi On 9/7/23 20:05, Niels Dossche wrote:
> I just noticed one small detail. > From the RFC text: "All tests were carried out using wall-power." I guess you mean wall-time? >
No, this means that the laptops whose CPUs where tested were plugged into the wall :-) I've added a parenthesis clarifying what that intends to mean. Best regards Tim Düsterhus

Craig Francis

2 years ago
On 7 Sep 2023, at 18:26, Tim Düsterhus <tim@bastelstu.be> wrote:
> in response to the recent "PASSWORD_DEFAULT value" thread [1], I've created an RFC to discuss an increase of the default BCrypt costs for `password_hash()` from the current value of 10. > > https://wiki.php.net/rfc/bcrypt_cost_2023
Thanks Tim, Just quickly running this on two AWS EC2 servers, to give rough figures for a VM (note usual issues like noisy neighbours, turbo-boost, thermal throttling, etc). t2.nano Cost 8: 2.083060 total (0.020831 per hash) Cost 9: 4.115596 total (0.041156 per hash) Cost 10: 8.238419 total (0.082384 per hash) Cost 11: 16.334089 total (0.163341 per hash) Cost 12: 32.693785 total (0.326938 per hash) Cost 13: 65.587982 total (0.655880 per hash) Cost 14: 131.358058 total (1.313581 per hash) t2.small Cost 8: 2.062625 total (0.020626 per hash) Cost 9: 4.142067 total (0.041421 per hash) Cost 10: 8.231646 total (0.082316 per hash) Cost 11: 16.851889 total (0.168519 per hash) Cost 12: 32.814440 total (0.328144 per hash) Cost 13: 69.409889 total (0.694099 per hash) Cost 14: 133.682196 total (1.336822 per hash) Both nano and small only have 1 vCPU, have 0.5 vs 1 GiB RAM, and a different number of CPU Credits/hr. We recently discussed hashing and costs at one of our OWASP meetings, we came to conclusion that the default of 10 for bcrypt probably should be increased, but only to 11 for typical websites. The main concern was about making denial-of-service attacks easier (think of a normal website developer, who won't limit the number of login attempts). It's also worth keeping in mind the difference between online vs offline attacks, what it's being used for, human behaviour when it comes to choosing bad passwords ("123456" and "Password1!" will still be guessed very quickly), etc. Craig

Hans Henrik Bergan

2 years ago
@Craig warning, it's very random what kind of CPU performance you get on your t2 instances, the CPUs vary greatly from modern to many years old. I know of Fortune 500 companies that have automated systems to spin up t2 instances until they randomly get "a good one", then discard the others, because the cpu performance vary so widely On Thu, 7 Sept 2023 at 23:38, Craig Francis <craig@craigfrancis.co.uk> wrote:

Unnamed Person

2 years ago
> On 09/07/2023 4:37 PM CDT Craig Francis <craig@craigfrancis.co.uk> wrote: > > We recently discussed hashing and costs at one of our OWASP meetings, we came to conclusion that the default of 10 for bcrypt probably should be increased, but only to 11 for typical websites. The main concern was about making denial-of-service attacks easier (think of a normal website developer, who won't limit the number of login attempts). >
I fought long and hard to get bcrypt down from cost 12 to only cost 10 even though cost 9 was over powered vs the other settings. At the time cost "8.1" was equivalent to the other settings. After the recent settings increase of the others, cost "8.7" is equivalent. Currently all of the OWASP settings come directly from me except bcrypt. The only way I was able to get it down to cost 10 was giving equivalent settings to cost 12 for the other algorithms. Just to show that those numbers were obviously too high. Note that bcrypt cost 12 is currently as strong as PBKDF2-HMAC-SHA256 with ~6,000,000 iterations. Which is an insane number for web auth. Anyway I don't look forward to arguing with OWASP to keep bcrypt at cost 10. Even though it's currently 2.5x stronger than the other accepted settings.

Alexandru Pătrănescu

2 years ago
On Thu, Sep 7, 2023 at 8:26 PM Tim Düsterhus <tim@bastelstu.be> wrote:
> Hi > > in response to the recent "PASSWORD_DEFAULT value" thread [1], I've > created an RFC to discuss an increase of the default BCrypt costs for > `password_hash()` from the current value of 10. > > https://wiki.php.net/rfc/bcrypt_cost_2023 > >
I think 12 looks reasonable. I've performed some tests myself on private hosted servers with newer hardware with good results for 12 around 0.1 seconds. Can this be integrated into PHP 8.3, as it's not a new feature that can cause problems? Pushing it to 8.4 will delay the real usage with 2-3 more years already. I feel like the hardware performance improvements (specifically single thread performance) slightly increased in the past 3-4 years, and soon most of the hosting providers will be using it. Thank you for looking into this. Having good security configuration by default is important. Regards, Alex

Tim Düsterhus

2 years ago
Hi On 9/8/23 18:49, Alexandru Pătrănescu wrote:
>> in response to the recent "PASSWORD_DEFAULT value" thread [1], I've >> created an RFC to discuss an increase of the default BCrypt costs for >> `password_hash()` from the current value of 10. >> >> https://wiki.php.net/rfc/bcrypt_cost_2023 >> >> > > I think 12 looks reasonable. > I've performed some tests myself on private hosted servers with > newer hardware with good results for 12 around 0.1 seconds.
wow, that is a 33% reduction even compared to the Xeon E-2246G and thus hard to believe. What CPU is that?
> Can this be integrated into PHP 8.3, as it's not a new feature that can > cause problems?
The release managers for PHP 8.3 would need to decide that. However I'd rather not include this in PHP 8.3 at this point.
> Pushing it to 8.4 will delay the real usage with 2-3 more years already.
IMO this is fine. Common frameworks can and do already use a different default. Symfony apparently is at 13 by default. Laravel uses 10, but I've already pinged someone on Mastodon to maybe have a look at the results of this RFC: https://phpc.social/@timwolla/111025125667858110 The current default of 10 is not insecure and rolling this out a little more slowly will mean that more and more of the old and slow hardware will be retired and replaced by modern hardware, lessening the impact.
> I feel like the hardware performance improvements (specifically single > thread performance) slightly increased in the past 3-4 years, and soon most > of the hosting providers will be using it. >
From my experience as a developer of a software that is commonly run on shared hosting, web hosters *love* their ancient hardware, because it's fully depreciated from a taxation / accounting PoV and every extra day it is used is "free money". Customers commonly are not able to tell they are running with tens of other customers on this ancient hardware and thus won't complain ("loading times of 1 second are fine"). Best regards Tim Düsterhus

Hans Henrik Bergan

2 years ago
>web hosters *love* their ancient hardware
No kidding. dreamhost.com host over 1.5 million websites, presumably most are on their "Shared Unlimited" package, which runs on AMD Opteron 4122, a high-end server CPU from 2010. Some benchmarks there: hanshenrik@jonathan-dayton:~$ cat /proc/cpuinfo | head processor : 0 vendor_id : AuthenticAMD cpu family : 16 model : 8 model name : AMD Opteron(tm) Processor 4122 stepping : 0 microcode : 0x10000da cpu MHz : 2200.000 cache size : 512 KB physical id : 0 hanshenrik@jonathan-dayton:~$ php -v PHP 8.2.5 (cli) (built: Apr 13 2023 18:45:57) (NTS) Copyright (c) The PHP Group Zend Engine v4.2.5, Copyright (c) Zend Technologies with Zend OPcache v8.2.5, Copyright (c), by Zend Technologies hanshenrik@jonathan-dayton:~$ hyperfine 'php -r '\''password_hash("password1234",PASSWORD_BCRYPT,["cost"=>9]);'\''' Benchmark 1: php -r 'password_hash("password1234",PASSWORD_BCRYPT,["cost"=>9]);' Time (mean ± σ): 122.7 ms ± 2.4 ms [User: 78.1 ms, System: 33.7 ms] Range (min … max): 120.0 ms … 127.5 ms 22 runs hanshenrik@jonathan-dayton:~$ hyperfine 'php -r '\''password_hash("password1234",PASSWORD_BCRYPT,["cost"=>10]);'\''' Benchmark 1: php -r 'password_hash("password1234",PASSWORD_BCRYPT,["cost"=>10]);' Time (mean ± σ): 166.4 ms ± 2.7 ms [User: 115.1 ms, System: 39.3 ms] Range (min … max): 163.0 ms … 171.2 ms 18 runs hanshenrik@jonathan-dayton:~$ hyperfine 'php -r '\''password_hash("password1234",PASSWORD_BCRYPT,["cost"=>11]);'\''' Benchmark 1: php -r 'password_hash("password1234",PASSWORD_BCRYPT,["cost"=>11]);' Time (mean ± σ): 246.0 ms ± 5.2 ms [User: 198.2 ms, System: 34.5 ms] Range (min … max): 241.0 ms … 256.5 ms 12 runs hanshenrik@jonathan-dayton:~$ hyperfine 'php -r '\''password_hash("password1234",PASSWORD_BCRYPT,["cost"=>12]);'\''' Benchmark 1: php -r 'password_hash("password1234",PASSWORD_BCRYPT,["cost"=>12]);' Time (mean ± σ): 409.7 ms ± 3.6 ms [User: 355.6 ms, System: 41.6 ms] Range (min … max): 405.3 ms … 416.6 ms 10 runs hanshenrik@jonathan-dayton:~$ hyperfine 'php -r '\''password_hash("password1234",PASSWORD_BCRYPT,["cost"=>13]);'\''' Benchmark 1: php -r 'password_hash("password1234",PASSWORD_BCRYPT,["cost"=>13]);' Time (mean ± σ): 729.3 ms ± 10.6 ms [User: 672.5 ms, System: 43.8 ms] Range (min … max): 717.3 ms … 754.5 ms 10 runs must say, surprisingly good performance for a 2010 cpu On Sun, Sep 10, 2023, 18:06 Tim Düsterhus <tim@bastelstu.be> wrote:

Tim Düsterhus

2 years ago
Hi On 9/12/23 17:56, Hans Henrik Bergan wrote:
>> web hosters *love* their ancient hardware > > No kidding. dreamhost.com host over 1.5 million websites, presumably most > are on their "Shared Unlimited" package, which runs on > AMD Opteron 4122, a high-end server CPU from 2010. > Some benchmarks there:
It appears your benchmarks are broken, because you're also measuring the startup cost of PHP itself. You should see an approximate doubling in time taken for each increase of the cost, but you have 122ms for 9 and 166ms for 10. A simple microtime(true) benchmark loop as used with my test script should be fine for ballpark estimates, as password_hash() is pretty heavy, dwarfing the measurement overhead. Best regards Tim Düsterhus

Hans Henrik Bergan

2 years ago
>you're also measuring the startup cost of PHP itself.
yup correct
>A simple microtime(true) benchmark loop as used with my test script should be fine for ballpark estimates
agreed
>dwarfing the measurement overhead.
wouldn't count out random cpu context switch/background noise completely, see my hyperfine benchmark for cost 13:
> Range (min … max): 717.3 ms … 754.5 ms 10 runs
- over 10 runs, the fastest was 717ms and the slowest was 754ms, so background noise made at least 37ms difference there.. but yeah anyway, here's from your script: hanshenrik@jonathan-dayton:~$ time php bench.php Cost 8: 2.022854 total (0.020229 per hash) Cost 9: 4.176210 total (0.041762 per hash) Cost 10: 8.121596 total (0.081216 per hash) Cost 11: 16.919405 total (0.169194 per hash) Cost 12: 33.059071 total (0.330591 per hash) Cost 13: 66.761731 total (0.667617 per hash) Cost 14: 140.695820 total (1.406958 per hash) real 4m31.854s user 4m13.115s sys 0m2.168s hanshenrik@jonathan-dayton:~$ cat /proc/cpuinfo | head (...) model name : AMD Opteron(tm) Processor 4122 On Tue, 12 Sept 2023 at 18:01, Tim Düsterhus <tim@bastelstu.be> wrote:

Alexandru Pătrănescu

2 years ago
On Sun, Sep 10, 2023 at 7:06 PM Tim Düsterhus <tim@bastelstu.be> wrote:
> Hi > > On 9/8/23 18:49, Alexandru Pătrănescu wrote: > > > > I think 12 looks reasonable. > > I've performed some tests myself on private hosted servers with > > newer hardware with good results for 12 around 0.1 seconds. > > wow, that is a 33% reduction even compared to the Xeon E-2246G and thus > hard to believe. What CPU is that? > >
That was a new Xeon Gold 5416S. I got lucky being able to run some tests on it before being pushed to production replacing a slightly older one, a Xeon Gold 5218. I'll be able to test that as well, but I feel like anyway the hardware I used is not what is usually in general. Actually, it is even less relevant, as it is meant to be used by a high performing MySQL server and not for running PHP.
> > Pushing it to 8.4 will delay the real usage with 2-3 more years already. > > IMO this is fine. Common frameworks can and do already use a different > default. Symfony apparently is at 13 by default. Laravel uses 10, but > I've already pinged someone on Mastodon to maybe have a look at the > results of this RFC: > > https://phpc.social/@timwolla/111025125667858110 > > The current default of 10 is not insecure and rolling this out a little > more slowly will mean that more and more of the old and slow hardware > will be retired and replaced by modern hardware, lessening the impact. > >
Understood, yes, I agree.
> > I feel like the hardware performance improvements (specifically single > > thread performance) slightly increased in the past 3-4 years, and soon > most > > of the hosting providers will be using it. > > > > From my experience as a developer of a software that is commonly run on > shared hosting, web hosters *love* their ancient hardware, because it's > fully depreciated from a taxation / accounting PoV and every extra day > it is used is "free money". Customers commonly are not able to tell they > are running with tens of other customers on this ancient hardware and > thus won't complain ("loading times of 1 second are fine"). > >
Yes, I think I evaluated the hardware upgrade lifecycle to be around 5 years, but in reality it's 10-15 years. And also the CPU options used by hosting providers are cost oriented, to get the most performance per dollar. Thank you, Alex

Tim Düsterhus

2 years ago
Hi On 9/7/23 19:26, Tim Düsterhus wrote:
> in response to the recent "PASSWORD_DEFAULT value" thread [1], I've > created an RFC to discuss an increase of the default BCrypt costs for > `password_hash()` from the current value of 10. > > https://wiki.php.net/rfc/bcrypt_cost_2023 > > This message is intended to officially open the discussion period for > that RFC.
The minimum 14 days of discussion will be over tomorrow. I believe the RFC is clearly written, sufficiently explains possible drawbacks and gives enough data to make an information decision. As such I don't expect any more meaningful discussion and plan open the vote shortly after the 14 days are actually over to get this off my list. Best regards Tim Düsterhus