清理用户密码
在散列和存储在我的数据库之前,我应该如何转义或清理用户提供的密码?
当PHP开发人员出于安全目的考虑对用户密码进行哈希处理时,他们通常倾向于将这些密码视为其他用户提供的数据。 这个问题经常出现在与密码存储相关的PHP问题中; 开发人员通常希望在使用escape_string()
(在各种迭代中), htmlspecialchars()
, addslashes()
等函数来清理密码并将其存储在数据库中之前,开发人员通常要清理密码。
您不应该对使用PHP的password_hash()
进行哈希处理的password_hash()
进行任何其他清理机制的修改或使用,其中最大的一个原因是因为对密码进行额外的清理需要不必要的额外代码。
你会争论(你可以在用户数据被接受用于你的系统的每一篇文章中看到它),我们应该清理所有的用户input,而且我们正在接受来自用户的其他信息。 密码是不同的。 哈希密码不能提供任何SQL注入威胁,因为string在存储到数据库中之前会变成哈希值。
哈希密码的行为是使密码安全地存储在您的数据库中的行为。 哈希函数没有赋予任何字节特殊含义,因此出于安全原因不需要清理其input
如果您遵循允许用户使用他们想要的密码/短语的口头禅,并且您不限制密码 ,允许任何长度,任何数量的空格和任何特殊字符散列将使密码/密码安全,无论内容是什么密码。 到目前为止,最常见的散列(默认值) PASSWORD_BCRYPT
将密码变成包含随机盐的60个字符宽的string以及散列密码信息和成本(创build散列的algorithm成本):
PASSWORD_BCRYPT用于使用CRYPT_BLOWFISHalgorithm创build新的密码哈希。 这总是会导致哈希使用“$ 2y $”crypt格式,它总是60个字符宽。
存储散列的空间要求随着向函数添加不同的散列方法而改变,所以最好在所存储的散列的列types上加大一些,例如VARCHAR(255)
或TEXT
。
你可以使用一个完整的SQL查询作为你的密码,它将被哈希,使得它不可执行的SQL引擎,例如,
SELECT * FROM `users`;
可能被哈希到$2y$10$1tOKcWUWBW5gBka04tGMO.BH7gs/qjAHZsC5wyG0zmI2C.KgaqU5G
让我们看看不同的消毒方法如何影响密码 –
密码是I'm a "dessert topping" & a <floor wax>!
(在这里没有显示密码末尾有5个空格。)
当我们应用以下修剪方法时,我们会得到一些不同的结果:
var_dump(trim($_POST['upassword'])); var_dump(htmlentities($_POST['upassword'])); var_dump(htmlspecialchars($_POST['upassword'])); var_dump(addslashes($_POST['upassword'])); var_dump(strip_tags($_POST['upassword']));
结果:
string(40) "I'm a "dessert topping" & a <floor wax>!" // spaces at the end are missing string(65) "I'm a "dessert topping" & a <floor wax>! " // double quotes, ampersand and braces have been changed string(65) "I'm a "dessert topping" & a <floor wax>! " // same here string(48) "I\'ma \"dessert topping\" & a <floor wax>! " // escape characters have been added string(34) "I'm a "dessert topping" & a ! " // looks like we have something missing
当我们将这些发送到password_hash()
会发生什么? 他们都被哈希,就像上面的查询一样。 当您尝试validation密码时,问题就出现了。 如果我们使用这些方法中的一个或多个,我们必须在将它们与password_verify()
进行比较之前重新使用它们。 以下将失败:
password_verify($_POST['upassword'], $hashed_password); // where $hashed_password comes from a database query
在使用密码validation的结果之前,您必须通过您select的清洗方法来运行张贴的密码。 这是一个不必要的步骤,并会使哈希没有更好的。
使用小于5.5的PHP版本? 您可以使用password_hash()
兼容包 。
你真的不应该使用MD5密码哈希 。
在对密码进行哈希处理之前,应按照RFC 7613第4节的规定对其进行规范化。 尤其是:
- 额外的映射规则:任何非ASCII空间的实例必须被映射到ASCII空间(U + 0020); 非ASCII空间是具有“Zs”Unicode统一类别(除U + 0020之外)的任何Unicode代码点。
和:
- 规范化规则:Unicode规范化表单C(NFC)必须应用于所有字符。
这将试图确保如果用户input相同的密码但使用不同的input方法,则密码仍应被接受。