Hello all,
Since the discussion has died down around the concept, I have updated the
RFC and moved it into Proposed (under discussion) status.
I have updated the RFC to include a section on discussion points containing
points that I know were raised but I felt were not closed (there was some
debate or disagreement). I tried to include a simple description of both
arguments, and the position the RFC currently takes and a brief reason why.
https://wiki.php.net/rfc/password_hash
Please have a look and provide any feedback!
Thanks!
Anthony
2012/7/12 Anthony Ferrara ircmaxell@gmail.com:
Hello all,
Since the discussion has died down around the concept, I have updated the
RFC and moved it into Proposed (under discussion) status.I have updated the RFC to include a section on discussion points containing
points that I know were raised but I felt were not closed (there was some
debate or disagreement). I tried to include a simple description of both
arguments, and the position the RFC currently takes and a brief reason why.https://wiki.php.net/rfc/password_hash
Please have a look and provide any feedback!
Hello Anthony,
I like your RFC. I can say this, because I wrote a similar project
about a year ago as a PHP-class and came to the same results.
No, that's not correct: Nearly the same results! There are small gaps
between my results and the suggested. I explain in detail in order of
"feeled priority".
[I don't had a look into the current C implementation, because I want
to keep my mind clean from the needs of the C-developers side: I want
to focus on the PHP-developer side.]
- The resulting string should have a version information. For example
the first char. the example hash will look like
"1$2y$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi",
instead of "$2y$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi"
Maybe it is legal to interpret a missing version as "this is version
1"? But it is important, that it has now a version for
future-compatibility. This is, becaus encryption is developed since I
program and will develop further within the next thousand years. With
a version-information we can guarantee that the algorithms can work,
even if the hash-format changes markable (because needed, because new
unforseeable aspects of encryption come in focus). In my project, this
version-information helped me to distinct between old password-hashes
and new ones.
[I think this is also a good argument against "password_hash() should
have no defaults", because this is a more than obvious sign to
everyone "hey, there could be a version 2, how will that look like?"]
2a) I'm not happy with the behavour to raise warnings. Maybe I'm
splitting hairs, but if there is one error, the chance is by
experience very big, that there is another. So, if a developer for
example will not check the results of password_hash()
, false is stored
in the database. And if he makes a second error (and the chance is as
said very big in this case), you may be able to log in with this or do
other ugly stuff. Don't say "impossible". I've seen things...
In my project I had really very good results, when I just throw
exceptions in the case that something goes wrong. This is the highly
visible sign for a bad developer, that he has made something wrong or
for a customer, installing a new version, that he now has a big
problem and should go back to the older version. I really want
exceptions here, because they prevent such missuse very effective and
cannot be overgone.
By minimim it should stop execution, if the password_hash()
or
password_verify()
is called wrong, because I think, this is more
secure than just to continue, which is in my eyes definitily a
mistake.
Maybe I'm wrong and this behaviour will make it possible to hack the
database? But I don't belive that...
With other words: I think how to deal with warnings in this
"potentially hazardous" methods needs a little bit more discussion and
I'm currently not satisfied with it, because it doesn't prevent stupid
errors.
2b) I don't like that the functions sometimes will return FALSE,
sometimes NULL. Not logical for PHP-developer and will lead by
guarantee to code which is checked wrong. Again: I would prefer to
fetch exceptions. If this is not possible I want either NULL
or FALSE
as result for all functions, but not NULL
or FALSE.
3a) I would await a function "password_algos()" (like hash_algos()
),
which returns me all available algorithms.
The available algorithms should also be displayed in PHPINFO()
. This
is because I need to check, if the current version has built it in.
3b) I don't like the encryption of the algorithm ("2y", WTF, what's
that? :) ). Look at the function hash_algos()
. There are full
qualified names of algorithms. Why don't use just the names? Is it,
because of some more bytes needed? :) Ok, I mean: why not using a good
name, so that someone can guess what it is, without knowing the docs?
That's just my thinking as PHP-developer, because this is not logical
for me to encrypt the encryption-algorithm. :)
3c) I think about changes. Password algorithms are a thing of changing
over time. So I would like to have a function like
"password_algo_info($algo)", which returns me as a developer a
detailed information about what this algorithm needs to work propper
and what the full description of this is (including e.g. an url, where
I can look for more information), because I think that this is
eventually a thing, which is extended rapidly and the documentation is
to slow to go with it. Or you are working with an older version in
which the algo works different. Not very important and maybe needs
more discussion. But I think something is here better than nothing.
Again: very low prio!
4a) I don't like the hole CONSTANT-stuff. I don't want to have a
doozen of fixed CONSTANTS, because I don't need them. The only
constant is, that the list of constants will rise. :)
Ok, more serious: I really don't need a constant for a thing, which is
currently known to be changed in future. If the password is always
stored with the currently most secure algorithm I don't need that.
And as a developer this is, what I want! I don't want to care about
the details, I want to be sure, that this is the currently most secure
way to do it. That's what I want. I don't want to know, which
algorithms exists. I don't need to choose between them. I just use
them, because some smarter guys than me have thought thouroughly about
what is most secure. :)
I can not think about an situation where I need to set it in my code
under normal circumstances. And if I really need to choose an
algorithm, it is better a configurable option in my program, thats
just good style. (For example a configuration-file, or a call-option.)
A constant means: It is fixed in my code. That's good, if it doesn't
change.
Another example: if I need to choose the algorithm as an
administrator, I choose it in my admin-interface from a select-field.
The value is then stored as as string and not as a constant-name. I
need to create that list of available algorithms. I don't need
constants.
The only situations, where constants may be needed are, if you write a
converter or something like that and even in this case constants won't
make the code better or more secure, they only help to prevent silly
programming mistakes. The real mistakes are: Development and
Production have slightly different versions. Or you may have a big
problem, if your IDE is not matching to the used PHP-version. If you
have constants, you will never program arround that. If you don't you
need to think about how it would be self-configuring...
In short: No real need for constant (except that you get warnings, if
you take a constant, which is not available, but see above: If needed,
it will be in a config-file as text). It would be another situation,
if this would be a feature, which will not change much over the time.
But it will.
I need to generate displayable lists and more intuitive algorithm
names than just "2y".
4b) I don't like the idea to change a constant (PASSWORD_DEFAULT) with
a new version of PHP. This may break in some ugly situation your hole
PHP-update, because you didn't thought about this change. :)
Again: I think, that chhoosing the best algorithm should normally not
be the job of the developer. I don't see the need.
But to make it possible I suggest to have a function
"password_best_algo()" instead, which returns a name of
password_algos(). Why a function instead of a constant? You can add a
parameter "$version" to this function and in this case the function
returns the best algorithm for that version of a password-hash. I
think this is eventually important, but maybe I'm looking too far into
the future or forgot to think this completly through.
- I added something like "is_password_hash()", to check, if a hash
has the right syntax (not semantic) to work with it. This prevents
internally also, that hashes with version 2 can work together with the
class for version 1.
- This is hair-splitting again, but least important: I don't like the
name "password*" for the functions. This is because the functions
don't return a password. Impractical names will give (some less
experienced developers) wrong ideas of what the functions may do.
It should be clear: This is a hash-function, you fill in a password
and get a hash.
But "hash*" is already used. I have no good solution for that and it
is not quite important, but how would it be with "pwhash*", "phash*"
or "hashpass"? Something good to remember...
Maybe needs further discussion, but as said: Not so important, maybe
someone has a good idea...
Some comments to the discussion points:
password_make_salt() Is Not Needed: I like that function, because it
can be used to generate a random password(). Just google for "generate
password" to see what I mean.
It should have a third mode, where the "/"-char is not included for
that case, because it may make problems. Maybe it is also a good idea
that you can pass a string, which includes the allowed chars for this
function. And because it can be used for completly other things than
just hashes or passwords I think renaming or an alias would be useful
e.g. "str_random()". (UTF8?)
password_needs_rehash()
is not needed: I think it's needed. Think
about 5 years from now: bcrypt() is found to be insecure. Now we have
to rebuild the hash. Not possible over night. Could be done while
logging in and checking if it needs rehashing with this function.
Again: This are only suggestions from the sight of an experienced
PHP-developer. It's totally clear, that you have another sight. But I
hope they are helpful.
Hope you are not too firm with me, I'm new to this list. :)
--
Alexander Aulbach
- The resulting string should have a version information. For example
the first char. the example hash will look like
"1$2y$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi",
instead of "$2y$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi"
See that 2y in the string? That's the version information. If a
different algorithm is used, a different string will be in there. This
also applies to changes to the algorithm itself. E.g. the 2y prefix is
already a modified version of the original bcrypt algorithm.
Nikita
2012/7/12 Nikita Popov nikita.ppv@gmail.com:
- The resulting string should have a version information. For example
the first char. the example hash will look like
"1$2y$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi",
instead of "$2y$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi"See that 2y in the string? That's the version information. If a
different algorithm is used, a different string will be in there. This
also applies to changes to the algorithm itself. E.g. the 2y prefix is
already a modified version of the original bcrypt algorithm.Nikita
Cool. "y" is the algorithm? I just ask to be sure. :)
How do I know which version I'm using? Think about checking if I'm
able to handle this version-hashes. Or other things like "generate a
hash for version 1 instead of version 2, because I know what I'm
doing". I mean: We can just fail with verify, but it would be
sometimes great to know, why it fails. :)
--
Alex Aulbach
Alex,
First off, thanks for such a thorough reply!!! Comments are inline.
- The resulting string should have a version information. For example
the first char. the example hash will look like
"1$2y$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi",
instead of "$2y$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi"Maybe it is legal to interpret a missing version as "this is version
1"? But it is important, that it has now a version for
future-compatibility. This is, becaus encryption is developed since I
program and will develop further within the next thousand years. With
a version-information we can guarantee that the algorithms can work,
even if the hash-format changes markable (because needed, because new
unforseeable aspects of encryption come in focus). In my project, this
version-information helped me to distinct between old password-hashes
and new ones.[I think this is also a good argument against "password_hash() should
have no defaults", because this is a more than obvious sign to
everyone "hey, there could be a version 2, how will that look like?"]
That's what $2y$ is for. It's a standard crypt()
prefix algorithm
identifier. For example you can use $1$ for md5, $5$ for sha256 and $6$ for
sha512 algorithms. In the future, if new algorithms are added, it would be
added as a new prefix for crypt()
...
2a) I'm not happy with the behavour to raise warnings. Maybe I'm
splitting hairs, but if there is one error, the chance is by
experience very big, that there is another. So, if a developer for
example will not check the results ofpassword_hash()
, false is stored
in the database. And if he makes a second error (and the chance is as
said very big in this case), you may be able to log in with this or do
other ugly stuff. Don't say "impossible". I've seen things...
While I understand your point, I'm not sure that's as big of a deal. All it
takes is a simple if statement. It's not like a warning will be raised and
the hash will still be generated. If a warning is raised, it'll return
false. That's easy to check for, and IMHO more of a documentation problem
than a problem we should solve here...
In my project I had really very good results, when I just throw
exceptions in the case that something goes wrong. This is the highly
visible sign for a bad developer, that he has made something wrong or
for a customer, installing a new version, that he now has a big
problem and should go back to the older version. I really want
exceptions here, because they prevent such missuse very effective and
cannot be overgone.
I want exceptions here too. But PHP doesn't use exceptions in its standard
library (aside from SPL), and I'm not sure this is a compelling enough case
to implement the first... I could be swayed, but I'm not sure the rest of
the team would.
By minimim it should stop execution, if the
password_hash()
or
password_verify()
is called wrong, because I think, this is more
secure than just to continue, which is in my eyes definitily a
mistake.
I think that halting execution if either function is called wrong is a bit
drastic. Again, I understand why, but I think it's a bit overkill in this
case...
2b) I don't like that the functions sometimes will return FALSE,
sometimes NULL. Not logical for PHP-developer and will lead by
guarantee to code which is checked wrong. Again: I would prefer to
fetch exceptions. If this is not possible I want eitherNULL
orFALSE
as result for all functions, but notNULL
or FALSE.
I don't either. But that's how the rest of the core works...
3a) I would await a function "password_algos()" (like
hash_algos()
),
which returns me all available algorithms.The available algorithms should also be displayed in
PHPINFO()
. This
is because I need to check, if the current version has built it in.
That's a very good addition. It could be defined as such:
array(
NAME => constant_value
)
So,
array(
'bcrypt' => `PASSWORD_BCRYPT`
)
I'll add that when I get a few minutes.
3b) I don't like the encryption of the algorithm ("2y", WTF, what's
that? :) ). Look at the function
hash_algos()
. There are full
qualified names of algorithms. Why don't use just the names? Is it,
because of some more bytes needed? :) Ok, I mean: why not using a good
name, so that someone can guess what it is, without knowing the docs?
That's just my thinking as PHP-developer, because this is not logical
for me to encrypt the encryption-algorithm. :)
It's the standard crypt()
format, which is available in almost every single
programming language out there today. Which makes interoperability really
easy.
I would be very hesitant to invent our own format here, especially for the
interoperability standpoint. There are standards that exist, and unless
there's a strong reason not to use them, we should...
3c) I think about changes. Password algorithms are a thing of changing
over time. So I would like to have a function like
"password_algo_info($algo)", which returns me as a developer a
detailed information about what this algorithm needs to work propper
and what the full description of this is (including e.g. an url, where
I can look for more information), because I think that this is
eventually a thing, which is extended rapidly and the documentation is
to slow to go with it. Or you are working with an older version in
which the algo works different. Not very important and maybe needs
more discussion. But I think something is here better than nothing.
Again: very low prio!
I'm not sure why this needs to be a function. Wouldn't the documentation on
the internet be enough for this?
4a) I don't like the hole CONSTANT-stuff. I don't want to have a
doozen of fixed CONSTANTS, because I don't need them. The only
constant is, that the list of constants will rise. :)
Ok, more serious: I really don't need a constant for a thing, which is
currently known to be changed in future. If the password is always
stored with the currently most secure algorithm I don't need that.
And as a developer this is, what I want! I don't want to care about
the details, I want to be sure, that this is the currently most secure
way to do it. That's what I want. I don't want to know, which
algorithms exists. I don't need to choose between them. I just use
them, because some smarter guys than me have thought thouroughly about
what is most secure. :)
And the common use-case should be that. But there are other use-cases that
are compelling enough to support. Use-cases such as requiring passwords to
be backwards compatible to older versions of PHP. Or requiring
compatibility with another environment (python, etc) which may not get the
new algorithm when PHP does. That's why the choice is there, and why it's
forced to be made by the developer...
I can not think about an situation where I need to set it in my code
under normal circumstances. And if I really need to choose an
algorithm, it is better a configurable option in my program, thats
just good style. (For example a configuration-file, or a call-option.)
A constant means: It is fixed in my code. That's good, if it doesn't
change.
A documentation issue...
Another example: if I need to choose the algorithm as an
administrator, I choose it in my admin-interface from a select-field.
The value is then stored as as string and not as a constant-name. I
need to create that list of available algorithms. I don't need
constants.
A problem that password_get_algos would solve...
...snip...
4b) I don't like the idea to change a constant (PASSWORD_DEFAULT) with
a new version of PHP. This may break in some ugly situation your hole
PHP-update, because you didn't thought about this change. :)
Again: I think, that chhoosing the best algorithm should normally not
be the job of the developer. I don't see the need.
But to make it possible I suggest to have a function
"password_best_algo()" instead, which returns a name of
password_algos(). Why a function instead of a constant? You can add a
parameter "$version" to this function and in this case the function
returns the best algorithm for that version of a password-hash. I
think this is eventually important, but maybe I'm looking too far into
the future or forgot to think this completly through.
The password_best_algo() thought is intriguing, but I guess I don't see the
changing constant to be a big deal. It's an informed choice the developer
has to make, which is better than complicating the API by making it take 3
or 4 function calls to hash a password (IMHO)...
- I added something like "is_password_hash()", to check, if a hash
has the right syntax (not semantic) to work with it. This prevents
internally also, that hashes with version 2 can work together with the
class for version 1.
There's no need. password_get_info()
could be used for it, and I'm not sure
that there's even a valid use-case for such a function. Can you elaborate
over why you would use such a function?
- This is hair-splitting again, but least important: I don't like the
name "password*" for the functions. This is because the functions
don't return a password. Impractical names will give (some less
experienced developers) wrong ideas of what the functions may do.It should be clear: This is a hash-function, you fill in a password
and get a hash.But "hash*" is already used. I have no good solution for that and it
is not quite important, but how would it be with "pwhash*", "phash*"
or "hashpass"? Something good to remember...
Maybe needs further discussion, but as said: Not so important, maybe
someone has a good idea...
And password_hash($password) doesn't communicate that the function hashes a
password? If this is really an issue, please suggest a better prefix, as I
can't think of one that's better without being cryptic...
Some comments to the discussion points:
password_make_salt() Is Not Needed: I like that function, because it
can be used to generate a random password(). Just google for "generate
password" to see what I mean.
It should have a third mode, where the "/"-char is not included for
that case, because it may make problems. Maybe it is also a good idea
that you can pass a string, which includes the allowed chars for this
function. And because it can be used for completly other things than
just hashes or passwords I think renaming or an alias would be useful
e.g. "str_random()". (UTF8?)
I've thought about passing in a string of allowed characters. The problem
with that is two fold:
-
It greatly increases the complexity of the algorithm for generating the
salt. Take a look at this:
https://github.com/ircmaxell/PHP-CryptLib/blob/master/lib/CryptLib/Core/BaseConverter.php -
There's no usecase right now for salts that are of a different format
(but if one is found, it can be added). PBKDF2 would use a raw salt, and
all the other crypt algorithms would use the other format. Where's the
other need for salting?
Again: This are only suggestions from the sight of an experienced
PHP-developer. It's totally clear, that you have another sight. But I
hope they are helpful.Hope you are not too firm with me, I'm new to this list. :)
I hope I was not too firm either. I like some of the suggestions, and I
think some of them have real merit. But others concern me... Looking
forward to everyone else's thoughts...
Anthony
2012/7/12 Anthony Ferrara ircmaxell@gmail.com:
That's what $2y$ is for. It's a standard
crypt()
prefix algorithm
identifier. For example you can use $1$ for md5, $5$ for sha256 and $6$ for
sha512 algorithms. In the future, if new algorithms are added, it would be
added as a new prefix forcrypt()
...
Ya, didn't know that - my lib was based on the hash-functions (5.3).
But I understand nearly.
Perhaps I oversee something, but how do I know, if I could process it
with this version of crypt?
In my project I had really very good results, when I just throw
exceptions in the case that something goes wrong. This is the highly
visible sign for a bad developer, that he has made something wrong orI want exceptions here too. But PHP doesn't use exceptions in its standard
library (aside from SPL), and I'm not sure this is a compelling enough case
to implement the first... I could be swayed, but I'm not sure the rest of
the team would.
Hum. I have arguments: developers tend to use the @-operator to
prevent disturbing error-messages. :)
Ok, serious: I don't like function where I cannot control what is
written to the logfiles.
For example: error messages in socket_open() can not be catched (its
quite difficult). But it's sometimes totally normal, that it will
fail. Think this is a design-failure in PHP, that it is so complicated
to catch the messages. But we go off-topic here.
I think that halting execution if either function is called wrong is a bit
drastic. Again, I understand why, but I think it's a bit overkill in this
case...
Ok, it's a little bit too much and solves not the problem.
3a) I would await a function "password_algos()" (like
hash_algos()
),
which returns me all available algorithms.The available algorithms should also be displayed in
PHPINFO()
. This
is because I need to check, if the current version has built it in.array( 'bcrypt' => `PASSWORD_BCRYPT` )
I'll add that when I get a few minutes.
Maybe more informations?
array(
'bcrypt' => array(
'id' => PASSWORD_BCRYPT,
'default' => true,
'name' => "BCrypt"
'url' => "http://en.wikipedia.org/wiki/Bcrypt",
'params' => array('cost','salt')
)
)
Not elegant, but something like that's what I mean with the
algo_info() .... self documention. see down...
It's the standard
crypt()
format, which is available in almost every single
programming language out there today. Which makes interoperability really
easy.I would be very hesitant to invent our own format here, especially for the
interoperability standpoint. There are standards that exist, and unless
there's a strong reason not to use them, we should...
Sorry, just didn't know that. But was pure intention not to read too
much into the details.
Maybe something which should be documented carefully...
3c) I think about changes. Password algorithms are a thing of changing
over time. So I would like to have a function like
"password_algo_info($algo)", which returns me as a developer a
detailed information about what this algorithm needs to work propper
I'm not sure why this needs to be a function. Wouldn't the documentation on
the internet be enough for this?
It's just an idea. Nothing really important, see above.
But to make it possible I suggest to have a function
"password_best_algo()" instead, which returns a name of
password_algos(). Why a function instead of a constant? You can add a
parameter "$version" to this function and in this case the functionThe password_best_algo() thought is intriguing, but I guess I don't see the
changing constant to be a big deal. It's an informed choice the developer
has to make, which is better than complicating the API by making it take 3
or 4 function calls to hash a password (IMHO)...
I found no real need. Forget it. In an object-oriented context it
would make more sense.
- I added something like "is_password_hash()", to check, if a hash
has the right syntax (not semantic) to work with it. This prevents
internally also, that hashes with version 2 can work together with the
class for version 1.There's no need.
password_get_info()
could be used for it, and I'm not sure
that there's even a valid use-case for such a function. Can you elaborate
over why you would use such a function?
I do not quite completly understand the version/algorithm here. I
think about fast checks for millions of hashes.
Hm. In my class, the string had a defined format. If it hadn't that
format, it needs to be converted. This function was to check that very
fast without parsing it. But yours is implemented in C, not PHP... if
you can check 50000 per minute with password_get_info()
I think it is
fast enough. :)
password? If this is really an issue, please suggest a better prefix, as I
can't think of one that's better without being cryptic...
Indeed, I have no better suggestions.
--
Greets Alex
Anthony Ferrara wrote:
I want exceptions here too. But PHP doesn't use exceptions in its standard
library (aside from SPL), and I'm not sure this is a compelling enough case
to implement the first... I could be swayed, but I'm not sure the rest of
the team would.
Somewhat off-topic, but is there a reason why not? It seems to me that
introducing a new API without using PHP's best method of error handling
(IMHO) is a little silly.
Ryan McCue
<http://ryanmccue.info/
Somewhat off-topic, but is there a reason why not? It seems to me that
introducing a new API without using PHP's best method of error handling
(IMHO) is a little silly.
I don't really trust exception throwing near password-managing functions.
Consider the following:
class UserLogin {
var $loggedIn = false;
function login() {
$row = SELECT * FROM user WHERE username =
escape_string($_POST['user']) ;
$this->checkPassword($row->password);
}
function checkPassword($pw_hash) {
if (password_verify($_POST['password'], $pw_hash)
$this->loggedIn = true;
}
}
The codebase does no global exception handling (because it doesn't throw
exceptions itself),
and also nobody configured the server not to show errors/exceptions
(some say it was
purposely setup to show them).
password_verify()
"errors" if the parameters are not strings or the hash
doesn't match a
known hash format.
Which kind of error should you use? errors or exceptions? Provide a
reasoned answer.
2012/7/13 Ángel González keisial@gmail.com:
The codebase does no global exception handling (because it doesn't throw
exceptions itself),
and also nobody configured the server not to show errors/exceptions
(some say it was
purposely setup to show them).
password_verify()
"errors" if the parameters are not strings or the hash
doesn't match a
known hash format.
Which kind of error should you use? errors or exceptions? Provide a
reasoned answer.
Exceptions and a blank page/empty body for the user should be the default.
Because:
Think of it like a printer: If the printer has an error, it will not
continue to work, to avoid any break. The user needs to open all paper
trays, look into them and remove eventually the paper before the
printer can continue. For a login it's the same kind of logic: If you
don't know what happened you need to look into any "tray". If you
implement more sensors (better exception handling), you may continue
without looking.
In detail:
- Normally the code has no error here. No real need for fetching exceptions.
- So, if there is an error, you don't know why (because you didn't fetch).
- Even if I know there was an error (password_hash() returns false): I
can not continue with any action, because I don't know why. - If you don't know the reason of an error, it is in this case an
error to continue, - which will be done automatically, if you don't fetch. Perfect.
- And to make it not obvious for a hacker to get sufficient
informations about the type of exception, it is the most secure way to
display no information to a possible invader.
I know this will break current behaviour completly. But it's the most
secure way to do. And security is the reason of this discussion.
To implement this we need for example a special type of exception (e.
g. "interface non_displayable"), which will remove the error-messages.
--
Alex
Hi Anthony:
I want exceptions here too. But PHP doesn't use exceptions in its standard
library (aside from SPL)
DateTime uses exceptions.
--Dan
--
T H E A N A L Y S I S A N D S O L U T I O N S C O M P A N Y
data intensive web and database programming
http://www.AnalysisAndSolutions.com/
4015 7th Ave #4, Brooklyn NY 11232 v: 718-854-0335
Hi!
Looks good. The only question I have is for password_make_salt() - do we
need the user to specify length? I think length is defined by the
algorithm in the most cases. Maybe convert it to password_make_salt(int
$salt_type = PASSWORD_SALT_BCRYPT, int $length)
with both arguments optional and one of salt types being
PASSWORD_SALT_OTHER which just generates given length?
--
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Stas,
https://wiki.php.net/rfc/password_hash
Looks good. The only question I have is for password_make_salt() - do we
need the user to specify length? I think length is defined by the
algorithm in the most cases. Maybe convert it to password_make_salt(int
$salt_type = PASSWORD_SALT_BCRYPT, int $length)
with both arguments optional and one of salt types being
PASSWORD_SALT_OTHER which just generates given length?
My only heistation there is that SALT_* specifies the format. So all of the
crypt()
hashes would use that format (a-zA-Z0-9./). Perhaps the name is
bad, and it should be SALT_CRYPT instead (but this has the assumption that
salt formats will never change for crypt()
)...
-- password_hash()
password_hash_rfc(string $password, int $algo, array $options = array())
My personal opinion is the api should be:
password_hash(string $password, string $secret = '', array $options =
array());
where $options['method'] = PASSWORD_METHOD_BCRYPT;
Some people mentioned that the method/algorithm in should be the api? What
was the problem if crypt()
stores the actual method/algorithm in the hash?
Using this api, we let crypt()
should a random salt value and we pick our
secret.
Say you have:
define('MY_HASHING_SECRET', 'hhtrg54~%$%4....long');
$password = '1234';
password_hash_rfc($password . MY_HASHING_SECRET, PASSWORD_METHOD_BCRYPT);
password_hash($password, MY_HASHING_SECRET);
Note here that in both cases we let crypt()
generate a random salt that is
different for every password and store in the password.
But our 'secret' that is appended to every password is not stored in a
database for example, it's in some ways similar to a private key.
-- password_make_salt()
I would remove the need for this function.
I think it's important the api emphasizes the importance of keeping a
'secret' + has the added value that every password hash is different with a
crypt()
salt.
Thoughts?
Say you have:
define('MY_HASHING_SECRET', 'hhtrg54~%$%4....long'); $password =
'1234';password_hash_rfc($password . MY_HASHING_SECRET,
PASSWORD_METHOD_BCRYPT); password_hash($password, MY_HASHING_SECRET);Note here that in both cases we let
crypt()
generate a random salt that
is different for every password and store in the password.But our 'secret' that is appended to every password is not stored in a
database for example, it's in some ways similar to a private key.-- password_make_salt()
Another comment about this, the 'secret' in this case in somewhat similar
the 'purpose' of the salt:
http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf
S = purpose || rv
P = password
What I'm proposing is:
S = rv (random value from crypt)
P = password || purpose
In the end, it's the same thing we're feeding into the hash (more data/bits)
Whatever api is used, I think it's important to allow appending this purpose
or secret that's not stored directly in the final crypt()
hash.
Jonathan,
On Tue, Jul 31, 2012 at 8:32 AM, Jonathan Bond-Caron jbondc@openmv.comwrote:
--
password_hash()
password_hash_rfc(string $password, int $algo, array $options = array())
My personal opinion is the api should be:
password_hash(string $password, string $secret = '', array $options =
array());where $options['method'] = PASSWORD_METHOD_BCRYPT;
Some people mentioned that the method/algorithm in should be the api? What
was the problem ifcrypt()
stores the actual method/algorithm in the hash?Using this api, we let
crypt()
should a random salt value and we pick our
secret.Say you have:
define('MY_HASHING_SECRET', 'hhtrg54~%$%4....long');
$password = '1234';password_hash_rfc($password . MY_HASHING_SECRET, PASSWORD_METHOD_BCRYPT);
password_hash($password, MY_HASHING_SECRET);Note here that in both cases we let
crypt()
generate a random salt that is
different for every password and store in the password.But our 'secret' that is appended to every password is not stored in a
database for example, it's in some ways similar to a private key.
Please see this section of the RFC:
https://wiki.php.net/rfc/password_hash#the_api_does_not_support_pepper
-- password_make_salt()
I would remove the need for this function.
I think it's important the api emphasizes the importance of keeping a
'secret' + has the added value that every password hash is different with a
crypt()
salt.Thoughts?
RFC:
https://wiki.php.net/rfc/password_hash#the_api_does_not_support_pepper
Thanks, I missed it...
I strongly disagree with this, the 'pepper' IMHO is a best practice for web
applications.
I prefer to live with the idea that an attacker may comprise some
database(s) in the 'cloud' but not the physical machine where you can store
the pepper either in a file, share memory etc...
As far as missing research papers, it's hard to do research on the benefit
of keeping something private. If/when databases do get hacked, it's rarely
released to the public how it happened.
When it comes to web applications, my opinion is odds are greater in SQL
injection / data theft success then gaining physical access to the machine.
#1 SQL Injection: https://www.owasp.org/index.php/Top_10_2010
Sure it's an added layer of security but it's hard to deny the 'pepper'
can't help protect passwords against the #1 risk for php/web applications.
A pepper in UNIX crypt()
itself would be obviously useless, the user already
has access to the physical machine (cat /etc/passwd).
Thanks, I missed it...
I strongly disagree with this, the 'pepper' IMHO is a best practice for web
applications.I prefer to live with the idea that an attacker may comprise some
database(s) in the 'cloud' but not the physical machine where you can store
the pepper either in a file, share memory etc...As far as missing research papers, it's hard to do research on the benefit
of keeping something private. If/when databases do get hacked, it's rarely
released to the public how it happened.When it comes to web applications, my opinion is odds are greater in SQL
injection / data theft success then gaining physical access to the machine.
#1 SQL Injection: https://www.owasp.org/index.php/Top_10_2010Sure it's an added layer of security but it's hard to deny the 'pepper'
can't help protect passwords against the #1 risk for php/web applications.A pepper in UNIX
crypt()
itself would be obviously useless, the user already
has access to the physical machine (cat /etc/passwd).
If you really want to use a secret you should encrypt the resulting
password hash with a proper encryption algorithm. Hashing algorithms
are not designed for this purpose.
Nikita
On Tue, Jul 31, 2012 at 10:28 AM, Jonathan Bond-Caron jbondc@openmv.comwrote:
RFC:
https://wiki.php.net/rfc/password_hash#the_api_does_not_support_pepperThanks, I missed it...
I strongly disagree with this, the 'pepper' IMHO is a best practice for web
applications.
Again, I have not seen this being said by any security or cryptography
expert.
I prefer to live with the idea that an attacker may comprise some
database(s) in the 'cloud' but not the physical machine where you can store
the pepper either in a file, share memory etc...
Ok. So I register an account before I get the database. Now the only thing
that I need to crack is the pepper (since I know the salt, hash and
original password for my sentinel account).
As far as missing research papers, it's hard to do research on the benefit
of keeping something private. If/when databases do get hacked, it's rarely
released to the public how it happened.
It's very easy to do research on that. There are mathematical proofs that
encryption is secure if the secret is secure. I've yet to see that done
with a "pepper" used in the manner that you're requesting...
When it comes to web applications, my opinion is odds are greater in SQL
injection / data theft success then gaining physical access to the machine.
#1 SQL Injection: https://www.owasp.org/index.php/Top_10_2010
Wrong. OWASP #1 is not SQL Injection. It's Injection. Including SQL
Injection, but also including other forms of injection (header injection,
script injection, etc).
And that doesn't count that many use SQL Injection as a gateway
towards privilege escalation which on many systems will hand them access to
the file-system...
Sure it's an added layer of security but it's hard to deny the 'pepper'
can't help protect passwords against the #1 risk for php/web applications.
I'm not denying the concept. I'm denying the implementation.The existing
algorithms expect to see a password. Not a password concatenated with a
secret. Sure, it sounds logical that it would make it more secure. But
cryptography is not based on what sounds logical. It's based on what's
proven. And if it's not proven, it's deemed to be insecure until proven
otherwise.
If you want to do it in your code, that's one thing. But unproven
cryptography has no business in a language level implementation.
Furthermore,
That link that you posted actually explains things quite a bit. The salt
value that's indicated there is actually defined as:
A non-secret binary value that is used as an input to the key
derivation function PBKDF specified in this Recommendation to
allow the generation of a large set of keys for a given password.
Now, what does that mean? To understand that, we need to understand what a
secret is. A secret is basically a piece of information that the algorithm
relies upon for security. Meaning that the algorithm is not secure if the
secret is known. A non-secret piece of information is one that the security
of the algorithm is not dependent upon. So encryption requires a secret, as
the security of the encryption depends on the key being secret (if it's
exposed, all security is broken). Since hashing is designed to use a
non-secret salt, the security of the hashing algorithm does not depend on
it being secret.
With all of that said, if you really want a secret in there, don't hijack
the hashing algorithm to do it. There are two somewhat decent alternatives:
HMAC the password with the secret prior to passing it to
password_hash()
/crypt(). HMAC is secure and is designed for this exact
purpose.
Or,
Encrypt the resulting hash with a secure encryption function (RIJNDAEL_128
- CBC) prior to inserting it in the database. That way, each component uses
standard algorithms as they were designed to be used.
But I want to stress something else. Properly managing secrets is VERY
difficult. It's not even really possible in PHP, due to the way
copy-on-write works, and how variables are removed. To implement this sort
of a system correctly is not something even highly competent developers can
typically do. It really is that difficult to get right.
Anthony
On Tue, Jul 31, 2012 at 10:28 AM, Jonathan Bond-Caron <HYPERLINK
I strongly disagree with this, the 'pepper' IMHO is a best practice
for web applications.Again, I have not seen this being said by any security or cryptography
expert.
Like I said IMHO, I'm not a security expect but I do think there needs to be
modern discussion around 'web password hashing'.
Ok. So I register an account before I get the database. Now the only thing
that I need to crack is the pepper (since I know the salt, hash and original
password for my sentinel account).
Fair enough ;)
It can still be a problem if the pepper is large + the crypt()
salt
With all of that said, if you really want a secret in there, don't
hijack the hashing algorithm to do it. There are two somewhat decent
alternatives:HMAC the password with the secret prior to passing it to
password_hash()
/crypt(). HMAC is secure and is designed for this
exact purpose.
Not so great:
password_hash_rfc( hash_hmac('md5', 'password', '1024-bytes secret') ) //
hmac is short (~ 160bits)
I guess you mean:
hash_hmac('md5', password_hash_rfc('password'), '1024-bytes secret')
But then there's no way to know all those crypt()
parameters, salt, cost,
etc...
Maybe a new api?
password_hash_hmac($password, $secret, $options = array());
Encrypt the resulting hash with a secure encryption function
(RIJNDAEL_128 + CBC) prior to inserting it in the database. That way,
each component uses standard algorithms as they were designed to be used.
That's fine, I feel this should be somewhat easier in php core (without the
need for openssl & al.)
It also comes with a cost of decrypting the hashes / not so great
But I want to stress something else. Properly managing secrets is VERY
difficult. It's not even really possible in PHP, due to the way
copy-on-write works, and how variables are removed. To implement this
sort of a system correctly is not something even highly competent
developers can typically do. It really is that difficult to get right.
Sure managing keys properly can be hard, simple cases:
$secret = MY_KEY;
$secret = file_get_contents('/security/key.pem');
Again I'm making the assumption that the attacking does not have access to
the file system.
Jonathan,
On Tue, Jul 31, 2012 at 12:01 PM, Jonathan Bond-Caron jbondc@openmv.comwrote:
On Tue, Jul 31, 2012 at 10:28 AM, Jonathan Bond-Caron <HYPERLINK
I strongly disagree with this, the 'pepper' IMHO is a best practice
for web applications.Again, I have not seen this being said by any security or cryptography
expert.Like I said IMHO, I'm not a security expect but I do think there needs to
be
modern discussion around 'web password hashing'.
I'm not against discussion. I'm against core implementations
(or recommendation) of non-vetted cryptographic processes...
Ok. So I register an account before I get the database. Now the only
thing
that I need to crack is the pepper (since I know the salt, hash and
original
password for my sentinel account).Fair enough ;)
It can still be a problem if the pepper is large + the
crypt()
salt
With all of that said, if you really want a secret in there, don't
hijack the hashing algorithm to do it. There are two somewhat decent
alternatives:HMAC the password with the secret prior to passing it to
password_hash()
/crypt(). HMAC is secure and is designed for this
exact purpose.Not so great:
password_hash_rfc( hash_hmac('md5', 'password', '1024-bytes secret') ) //
hmac is short (~ 160bits)
In that case, the HMAC would produce exactly 128 bits of output.
Why would you use MD5 for that? Use SHA512. That gives you (in your case) a
128 character password (or 64 if you pass true to the third parameter,
which you should).
Also, be aware that BCrypt only uses the first 72 characters of the
password field. So if you use a hex encoded sha512 output, a good deal of
entropy would be lost (almost half of it)...
I guess you mean:
hash_hmac('md5', password_hash_rfc('password'), '1024-bytes secret')
But then there's no way to know all those
crypt()
parameters, salt, cost,
etc...
Absolutely not. That would make the hash unverifiable...
Maybe a new api?
password_hash_hmac($password, $secret, $options = array());
Again, implementing something in the core that's not verified and can't be
implemented well by the vast majority of developers out there. So a big -1
from me...
Encrypt the resulting hash with a secure encryption function
(RIJNDAEL_128 + CBC) prior to inserting it in the database. That way,
each component uses standard algorithms as they were designed to be used.That's fine, I feel this should be somewhat easier in php core (without the
need for openssl & al.)It also comes with a cost of decrypting the hashes / not so great
Huh? How is that not great? The encryption is actually quite fast... And
you actually want to slow down password hashing (to make it more difficult
to brute force), so I fail to see how this is an issue...
But I want to stress something else. Properly managing secrets is VERY
difficult. It's not even really possible in PHP, due to the way
copy-on-write works, and how variables are removed. To implement this
sort of a system correctly is not something even highly competent
developers can typically do. It really is that difficult to get right.Sure managing keys properly can be hard, simple cases:
$secret = MY_KEY;
$secret = file_get_contents('/security/key.pem');
Actually, that's not properly managing the key. It requires the web server
user to be able to read the key. That allows anyone who gains permissions
as the web server (even on a different vhost) to be able to get your key.
Properly managing it would require either a dedicated cryptography server
to handle it for you, or a dedicated piece of hardware to manage the key.
Anything less is just security through obscurity...
Again I'm making the assumption that the attacking does not have access
to
the file system.
Actually, you need to make the reverse assumption. You want to make the
data secure even if the attacker gets access to the filesystem. Now
obviously if they inject code into the stack they'll be able to view the
raw password from the user. But that requires long term access (and write
access). But the data stored should be protected even if the filesystem is
compromised...
Jonathan,
On Tue, Jul 31, 2012 at 12:01 PM, Jonathan Bond-Caron jbondc@openmv.comwrote:
Sure managing keys properly can be hard, simple cases:
$secret = MY_KEY;
$secret = file_get_contents('/security/key.pem');Actually, that's not properly managing the key. It requires the web server
user to be able to read the key. That allows anyone who gains permissions
as the web server (even on a different vhost) to be able to get your key.Properly managing it would require either a dedicated cryptography server
to handle it for you, or a dedicated piece of hardware to manage the key.
Anything less is just security through obscurity...
If there are several vhosts in that server, they should run with
different uids.
Assuming the file is 600/400, that should be good.
I don't think a crypto store would be much useful if once you become the
web server you can decrypt everything.
It would help in case of a read-only compromise of the full filesystem,
such a
leakage of the disk backups (but then, those backups would be incomplete,
as you couldn't restore them in a different machine either, and your whole
system relies on that piece of hardware not breaking...).
I think a better method would be to use an external suid binary similar to
unix_chkpwd which handles password_hash()
and password_verify()
for you.
It could encrypt the hash with a secret before returning it to you, but
as its
password_verify interface would only return yes/no, breaking on the db
wouldn't
expose the passwords without also breaking into the uid that program is
running as.
If you want to get fancy, that program could lock itself if it detects
it's being called
with an higher frequency than the throttling the webserver should be
applying (and
thus is potentially compromised...).
snip
Also, be aware that BCrypt only uses the first 72 characters of the
password field. So if you use a hex encoded sha512 output, a good deal of
entropy would be lost (almost half of it)...
Seeing as the hashing function will default (at first, at least) to
bcrypt, would it be possible to add a warning if it's given an input
longer than 72 chars? Preferably make the function context-aware so
you don't get the same warning if using sha512. Otherwise I predict
that someone will do:
$hash = password_hash($my_128_char_pepper . $password, PASSWORD_DEFAULT);
Which obviously renders the hashing useless, as you'll be hashing the
same 72 chars over and over again. Which, currently, crypt()
let's you
get away with without as much as a hiccup.
Regards
Peter
--
<hype>
WWW: plphp.dk / plind.dk
CV: careers.stackoverflow.com/peterlind
LinkedIn: plind
Twitter: kafe15
</hype
Peter,
snip
Also, be aware that BCrypt only uses the first 72 characters of the
password field. So if you use a hex encoded sha512 output, a good deal of
entropy would be lost (almost half of it)...Seeing as the hashing function will default (at first, at least) to
bcrypt, would it be possible to add a warning if it's given an input
longer than 72 chars? Preferably make the function context-aware so
you don't get the same warning if using sha512. Otherwise I predict
that someone will do:$hash = password_hash($my_128_char_pepper . $password, PASSWORD_DEFAULT);
Which obviously renders the hashing useless, as you'll be hashing the
same 72 chars over and over again. Which, currently,crypt()
let's you
get away with without as much as a hiccup.
That's actually a very good idea.
I'm curious though. Should we warning? Or should we sha512 hash (to bring
down to 64 chars)... That's something I think would be worth reaching out
to the crypt()
maintainers for advice...
Peter,
snip
Also, be aware that BCrypt only uses the first 72 characters of the
password field. So if you use a hex encoded sha512 output, a good deal
of
entropy would be lost (almost half of it)...Seeing as the hashing function will default (at first, at least) to
bcrypt, would it be possible to add a warning if it's given an input
longer than 72 chars? Preferably make the function context-aware so
you don't get the same warning if using sha512. Otherwise I predict
that someone will do:$hash = password_hash($my_128_char_pepper . $password, PASSWORD_DEFAULT);
Which obviously renders the hashing useless, as you'll be hashing the
same 72 chars over and over again. Which, currently,crypt()
let's you
get away with without as much as a hiccup.That's actually a very good idea.
I'm curious though. Should we warning? Or should we sha512 hash (to bring
down to 64 chars)... That's something I think would be worth reaching out
to thecrypt()
maintainers for advice...
I'd be wary of not doing what people actually expect - i.e. hash the
provided string with the specified algo. Better to educate the users,
I'd say, through a warning. Anyway, as you said, would be good to get
other opinions on this.
Regards
Peter
--
<hype>
WWW: plphp.dk / plind.dk
CV: careers.stackoverflow.com/peterlind
LinkedIn: plind
Twitter: kafe15
</hype
Peter,
snip
Also, be aware that BCrypt only uses the first 72 characters of the
password field. So if you use a hex encoded sha512 output, a good deal
of
entropy would be lost (almost half of it)...Seeing as the hashing function will default (at first, at least) to
bcrypt, would it be possible to add a warning if it's given an input
longer than 72 chars? Preferably make the function context-aware so
you don't get the same warning if using sha512. Otherwise I predict
that someone will do:$hash = password_hash($my_128_char_pepper . $password, PASSWORD_DEFAULT);
Which obviously renders the hashing useless, as you'll be hashing the
same 72 chars over and over again. Which, currently,crypt()
let's you
get away with without as much as a hiccup.
That's actually a very good idea.I'm curious though. Should we warning? Or should we sha512 hash (to bring
down to 64 chars)... That's something I think would be worth reaching out
to thecrypt()
maintainers for advice...
I'd be wary of not doing what people actually expect - i.e. hash the
provided string with the specified algo. Better to educate the users,
I'd say, through a warning. Anyway, as you said, would be good to get
other opinions on this.Regards
Peter
I'd go with the hashing. I'd would however produce a slightly different
prefix
than with bare bcrypt.
$password is user-provided. The library client shouldn't need to know
the hash
internals and -depending on that- truncate the output.
There may be a $option to disable this additional hashing, though.
2012/8/1 Ángel González keisial@gmail.com:
I'd go with the hashing. I'd would however produce a slightly different
prefix
than with bare bcrypt.
Like that. And I thought some about it. Currently, there is no real
need for that. And no one is hindered to implement his own
version-information into it.
But to do this right, there is a lack of information. This brought me
to an good idea:
a constant PASSWORD_VERSION
The current version-number of password-functions. You're free to store
this information with the hash (e. g. '$$' . PASSWORD_VERSION .
password_hash()
..., of course remove it before verify!).
Every change (new algorithms etc) will increment the version. This can
help to detect the case when in version 79 bcrypt is removed because
too insecure/too old.
As said, currently not needed, but if someone likes to, here it is. :)
--
Alex Aulbach
Also, be aware that BCrypt only uses the first 72 characters of the
password field. So if you use a hex encoded sha512 output, a good deal
of entropy would be lost (almost half of it)...
Good to know, do most hash algorithms have limitations on the # of chars as
input?
That would explain why (password || key) into a hash function has
limitations.
Jonathan,
Again, implementing something in the core that's not verified and
can't be implemented well by the vast majority of developers out
there.
Alright so I found some people supporting my claims:
http://blog.mozilla.org/webappsec/2011/05/10/sha-512-w-per-user-salts-is-not
-enough/
http://blog.mozilla.org/webdev/2012/06/08/lets-talk-about-password-storage/
It looks like Mozilla is using what you suggested, to be honest I don't
quite understand the difference between:
a) password_hash_rfc( hash_hmac('sha-512', 'password', '1024-bytes secret')
);
b) password_hash_rfc('password' . '1024-bytes secret' );
It seems to me that (b) would more computationally expensive to break since
you have more bytes in a slower algo.
Interestingly enough, there was a proposal for MD6 to be a keyed hash (with
pepper)
http://people.csail.mit.edu/rivest/pubs/RABCx08.pdf (3.5 A keyed hash
function)
There does seem to be some research on keyed hash functions here (4.2 MAC
construction):
http://research.microsoft.com/pubs/64588/hash_survey.pdf
But this use case has nothing to do with securing passwords
SHA1(k||M)
I guess my final point is a lot of code out there already do hash passwords
with a secret key, it would be nice to have that facility in PHP core.
Hello all,
Since the discussion has died down around the concept, I have updated the
RFC and moved it into Proposed (under discussion) status.I have updated the RFC to include a section on discussion points
containing points that I know were raised but I felt were not closed (there
was some debate or disagreement). I tried to include a simple description
of both arguments, and the position the RFC currently takes and a brief
reason why.https://wiki.php.net/rfc/password_hash
Please have a look and provide any feedback!
I've removed the password_make_salt() function from being exposed and
updated the RFC to indicate such. It can be added as a later change if
needed.
I plan on opening the vote on this next week, so if there's anything else
anyone wants to discuss, please speak up!
Anthony
Hello all,
Since the discussion has died down around the concept, I have updated the
RFC and moved it into Proposed (under discussion) status.I have updated the RFC to include a section on discussion points
containing points that I know were raised but I felt were not closed (there
was some debate or disagreement). I tried to include a simple description
of both arguments, and the position the RFC currently takes and a brief
reason why.https://wiki.php.net/rfc/password_hash
Please have a look and provide any feedback!
I've removed the password_make_salt() function from being exposed and
updated the RFC to indicate such. It can be added as a later change if
needed.I plan on opening the vote on this next week, so if there's anything else
anyone wants to discuss, please speak up!
Yes -- this is something that has been coincidentally discussed on a private list that I run.
One thing that we thought was a good idea was to have a site salt. This salt
would be applied in the same way (and in addition to) as the password specific
salt. The point is that this salt is NOT stored with/in the password hash, it should not
be stored in the database at all - thus making a cracker have to do more than
steal the database of encrypted/hashed password records.
There needs to be a way of specifying this, perhaps the array() to
password_hash()
could take an (optional) 'sitesalt' member that would be applied
if it were present.
Slight complication: since it is nice to be able to change the site salt
occasionally, the user/password record would need to contain a column
'siteSaltVersion' this would be a simple number that is incremented every time
that the site salt is changed. This would allow old passwords to be checked and
(probably) silently re-encrypted/hashed the next time that the user logged in.
Also: the RFC (or final documentation) should state how long the returned string
will be, so that the programmer knows how big the database_column/whatever
that the returned string is stored in should be.
--
Alain Williams
Linux/GNU Consultant - Mail systems, Web sites, Networking, Programmer, IT Lecturer.
+44 (0) 787 668 0256 http://www.phcomp.co.uk/
Parliament Hill Computers Ltd. Registration Information: http://www.phcomp.co.uk/contact.php
#include <std_disclaimer.h
Hello all,
Since the discussion has died down around the concept, I have updated
the
RFC and moved it into Proposed (under discussion) status.I have updated the RFC to include a section on discussion points
containing points that I know were raised but I felt were not closed
(there
was some debate or disagreement). I tried to include a simple
description
of both arguments, and the position the RFC currently takes and a brief
reason why.https://wiki.php.net/rfc/password_hash
Please have a look and provide any feedback!
I've removed the password_make_salt() function from being exposed and
updated the RFC to indicate such. It can be added as a later change if
needed.I plan on opening the vote on this next week, so if there's anything else
anyone wants to discuss, please speak up!Yes -- this is something that has been coincidentally discussed on a
private list that I run.One thing that we thought was a good idea was to have a site salt. This
salt
would be applied in the same way (and in addition to) as the password
specific
salt. The point is that this salt is NOT stored with/in the password hash,
it should not
be stored in the database at all - thus making a cracker have to do more
than
steal the database of encrypted/hashed password records.There needs to be a way of specifying this, perhaps the array() to
password_hash()
could take an (optional) 'sitesalt' member that would be
applied
if it were present.Slight complication: since it is nice to be able to change the site salt
occasionally, the user/password record would need to contain a column
'siteSaltVersion' this would be a simple number that is incremented every
time
that the site salt is changed. This would allow old passwords to be
checked and
(probably) silently re-encrypted/hashed the next time that the user logged
in.Also: the RFC (or final documentation) should state how long the returned
string
will be, so that the programmer knows how big the database_column/whatever
that the returned string is stored in should be.
https://wiki.php.net/rfc/password_hash#the_api_does_not_support_pepper
--
Ferenc Kovács
@Tyr43l - http://tyrael.hu