在散列用户提供的密码并将其存储在数据库中之前,我应该如何转义或清除这些密码?

当PHP开发人员考虑为安全目的散列用户密码时,他们往往倾向于想到这些密码,就像他们将提供任何其他用户提供的数据一样.这个主题经常出现在与密码存储相关的PHP问题中;开发人员通常希望在散列密码并将其存储在数据库中之前,使用诸如escape_string()(在各种迭代中)、htmlspecialchars()addslashes()等函数来清除密码.

推荐答案

你永远不应该逃避、修剪或使用任何其他清除密码的机制,你将使用PHP的password_hash()进行哈希运算,原因有很多,其中最大的一个原因是,对密码进行额外的清除需要不必要的额外代码.

你会争辩说(你在每一篇接受用户数据在你的系统中使用的帖子中都会看到),我们应该清理所有用户输入,而你对我们从用户那里接受的所有其他信息都是正确的.密码是不同的.Hashed passwords cannot offer any SQL injection threat because the string is turned into hash prior to storing in the database.

散列密码的行为是使密码安全地存储在数据库中的行为.哈希函数没有赋予任何字节特殊的含义,因此出于安全原因,不需要清除其输入

如果你遵循允许用户使用他们想要的passwords / phrasesdon't limit passwords的咒语,允许任意长度、任意数量的空格和任何特殊字符哈希将使密码/密码短语安全,无论密码中包含什么.到目前为止,最常见的散列(默认值)PASSWORD_BCRYPT将密码转换为一个60个字符宽的字符串,其中包含随机salt、散列密码信息和成本(创建散列的算法成本):

password_bcrypt用于使用crypt_blowfish算法创建新的密码散列.这将始终导致使用"$2y$"加密格式的散列,该格式始终为60个字符宽.

随着向函数添加不同的散列方法,存储散列的空间要求可能会发生变化,因此,存储的散列的列类型(如VARCHAR(255)TEXT)越大越好.

您可以使用完整的SQL查询作为您的密码,它将被散列,使其无法由SQL引擎执行,例如,

SELECT * FROM `users`;

可以散列到$2y$10$1tOKcWUWBW5gBka04tGMO.BH7gs/qjAHZsC5wyG0zmI2C.KgaqU5G

Let's see how different sanitizing methods affect the password -

密码为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 &quot;dessert topping&quot; &amp; a &lt;floor wax&gt;!     " // double quotes, ampersand and braces have been changed
string(65) "I'm a &quot;dessert topping&quot; &amp; a &lt;floor wax&gt;!     " // same here
string(48) "I\'m a \"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()时会发生什么?它们都会被散列,就像上面的查询一样.当你试图验证密码时,问题就出现了.如果我们使用其中一种或多种方法,我们必须在将它们与password_verify()进行比较之前重新使用它们.以下操作将失败:

password_verify($_POST['upassword'], $hashed_password); // where $hashed_password comes from a database query

在使用密码验证的结果之前,您必须通过您 Select 的清除方法运行发布的密码.这是一组不必要的步骤,并且不会使散列变得更好.


使用低于5.5的PHP版本?你可以使用password_hash()-compatibility pack.

你真的不应该用MD5 password hashes.

Php相关问答推荐

添加自定义Metabox到WooCommerce管理订单,启用HPOS

从产品中获取WooCommerce产品属性单选按钮的列表WP_Query

PHP如何将ARRAY_MAP与Reset()配合使用

在没有谷歌云客户端PHP库的情况下将图像上传到PHP中的Google存储API?

在内部API请求之后,在响应客户端之前,是否忘记了PHP中的Header()?

在没有symfony应用程序的情况下使用安全Bundle 包时,缺少配置构建器类

在WooCommerce中设置带有国家/地区和年份前缀的顺序序号

Wordpress,配置一周第一天选项

在 Woocommerce 邮箱订单中显示产品 GTIN

使用自定义插件中的 WooCommerce 模板发送自定义邮箱

当我激活插件时出现错误注意:未定义的偏移量:1

为什么 debug_backtrace() 不返回任何内容?

循环中未序列化数组显示的问题

优化后的标题:如何在WooCommerce我的帐户编辑表单中添加账单字段

PDO 和 SQL 查询结果中日期格式不同的原因可能是什么?

Laravel Docker 几个数据库

一个php应用程序可以实例化多个RNG吗

使用 v-for 的存储链接中的 Img src 在 Laravel vuejs 中不起作用

如何在 Laravel 9 中判断异常是否可报告?

如何简化 php API 中的格式化数组列表数据以提供 React Native 部分列表