-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Security] Add NativePasswordEncoder #31140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Todo:
|
src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php
Outdated
Show resolved
Hide resolved
is there any reason to keep |
I don't think so, we should deprecate it in 4.4 |
adcef7e
to
40f1daf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR ready
@@ -416,11 +416,14 @@ private function addEncodersSection(ArrayNodeDefinition $rootNode) | |||
->integerNode('cost') | |||
->min(4) | |||
->max(31) | |||
->defaultValue(13) | |||
->defaultNull() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The defaults belong to the implementation now, not to the configuration.
->end() | ||
->scalarNode('memory_cost')->defaultNull()->end() | ||
->scalarNode('time_cost')->defaultNull()->end() | ||
->scalarNode('threads')->defaultNull()->end() | ||
->scalarNode('threads') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
libsodium hardcodes threads to 1, and this makes sense in PHP too.
@@ -532,6 +533,10 @@ private function createEncoder($config, ContainerBuilder $container) | |||
return new Reference($config['id']); | |||
} | |||
|
|||
if ('auto' === $config['algorithm']) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"auto" should be the recommended default - I'm going to submit it as a recipe
'class' => NativePasswordEncoder::class, | ||
'arguments' => [ | ||
$config['time_cost'], | ||
(($config['memory_cost'] ?? 0) << 10) ?: null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
memory_cost (from password_hash) is in kib
but SodiumPasswordEncoder and NativePasswordEncoder accept bytes - this makes the conversion
{ | ||
$cost = $cost ?? 13; | ||
$opsLimit = $opsLimit ?? max(6, \defined('SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE') ? \SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE : 6); | ||
$memLimit = $memLimit ?? max(64 * 1024 * 1024, \defined('SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE') ? \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE : 64 * 1024 * 1024); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Argon2 with opslimit = 6 & memlimit=64MiB roughly operate in the same amount of time as BCrypt's cost=13
Also, in PHP7.4 SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE=6 and SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE=32MiB
So our defaults are a bit more strict than PHP 7.4, which matches the fact that a cost=13 for BCrypt is stricter than PHP's default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wondering about using SODIUM Constants in the Native Encoder, as what happens if PHP >7.2 but Sodium is NOT installed. Native should work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code above checks that SODUM_*
constants are defined before using them, and fallback to sensible defaults (equivalent hardcoded values) otherwise
throw new \InvalidArgumentException('$cost must be in the range of 4-31.'); | ||
} | ||
|
||
$this->algo = \defined('PASSWORD_ARGON2I') ? max(PASSWORD_DEFAULT, \defined('PASSWORD_ARGON2ID') ? PASSWORD_ARGON2ID : PASSWORD_ARGON2I) : PASSWORD_DEFAULT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PASSWORD_ARGON2ID > PASSWORD_ARGON2I > PASSWORD_BCRYPT, unless PASSWORD_DEFAULT is set to an even higher algo in the future
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if the argon algo is available the native encoder and the sodium encoder basically do the same thing?
I am wondering if it would be better for DX to use only PASSWORD_DEFAULT in the native encoder.
Then the config would become:
auto => use best supported / recommended encoder
native => use php default algo
sodium => use best supported / available sodium algo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think always using the best available algo is required for best security. I don't understand how that relates to DX.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think always using the best available algo is required for best security.
Agreed.
I don't understand how that relates to DX.
I just think it might be confusing that there are 2 encoders that can do the same thing (encode with the argon algo).
src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php
Outdated
Show resolved
Hide resolved
@@ -532,6 +533,10 @@ private function createEncoder($config, ContainerBuilder $container) | |||
return new Reference($config['id']); | |||
} | |||
|
|||
if ('auto' === $config['algorithm']) { | |||
$config['algorithm'] = SodiumPasswordEncoder::isSupported() ? 'sodium' : 'native'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the sodium encoder superior to our native encoder? Is that why it's preferred?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, in two aspects: it is faster for the same cost parameters, and it can be more up to date than the native one, as an extension can move faster to new algos.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
being faster for the same cost may not actually be superior. The whole point of a password hashing algorithm is that it should not be too fast.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
being faster for the same cost may not actually be superior. The whole point of a password hashing algorithm is that it should not be too fast.
this answer is wrong ;)
what matters is that attackers must spend significant resources to compute password hashes when they leaked. Being faster for the same cost is just improving UX and reducing greenhouse emissions. So yes, it matters a lot.
4fcca31
to
6aa50d1
Compare
1c79f90
to
406660f
Compare
406660f
to
04de8fe
Compare
src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
Outdated
Show resolved
Hide resolved
src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php
Show resolved
Hide resolved
src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
Show resolved
Hide resolved
04de8fe
to
9c1b4ce
Compare
src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php
Outdated
Show resolved
Hide resolved
9c1b4ce
to
28f7961
Compare
Thank you @nicolas-grekas. |
This PR was merged into the 4.3-dev branch. Discussion ---------- [Security] Add NativePasswordEncoder | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - This PR adds a new `NativePasswordEncoder` that defaults to the best available hashing algo to `password_hash()`. Best is determined by "us" or "php", the goal being that this will change in the future as new algos are published. This provides a native encoder that we should recommend using by default. Commits ------- 28f7961 [Security] Add NativePasswordEncoder
… NativePasswordEncoder (nicolas-grekas) This PR was merged into the 4.3-dev branch. Discussion ---------- [Security] deprecate BCryptPasswordEncoder in favor of NativePasswordEncoder | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | yes | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Follow up of #31140 Commits ------- e197398 [Security] deprecate BCryptPasswordEncoder in favor of NativePasswordEncoder
This PR adds a new
NativePasswordEncoder
that defaults to the best available hashing algo topassword_hash()
. Best is determined by "us" or "php", the goal being that this will change in the future as new algos are published.This provides a native encoder that we should recommend using by default.