清理用户密码

Jay*_*ard 95 php sql hash pdo

在散列它们并将它们存储在我的数据库中之前,我应该如何逃避或清除用户提供的密码?

当PHP开发人员考虑出于安全目的而考虑哈希用户的密码时,他们往往会像对待任何其他用户提供的数据一样考虑这些密码.这个主题经常出现在与密码存储相关的PHP问题中; 开发人员经常希望使用诸如escape_string()(在各种迭代中)等功能清理密码htmlspecialchars(),addslashes()然后再对其进行散列并将其存储在数据库中.

Jay*_*ard 97

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

您将争辩(并且您在用户数据被接受在您的系统中使用的每个帖子中都会看到它)我们应该清理所有用户输入,并且您对我们接受用户的其他所有信息都是正确的.密码不同.散列密码不能提供任何SQL注入威胁,因为字符串在存储到数据库之前会变为散列.

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

如果您遵循允许用户使用他们想要的密码/短语的咒语,并且您不限制密码,允许任何长度,任意数量的空格和任何特殊字符散列将使密码/密码安全无论内容中包含什么密码.截至目前最常见的哈希值(默认值),PASSWORD_BCRYPT将密码转换为60字符宽的字符串,其中包含随机盐以及散列密码信息和成本(创建哈希的算法成本):

PASSWORD_BCRYPT用于使用CRYPT_BLOWFISH算法创建新的密码哈希值.这将始终导致使用"$ 2y $"crypt格式的哈希值,该格式总是60个字符宽.

用于存储的哈希空间要求若有变更为不同的散列方法是添加到函数,所以它始终是更好地去列类型较大的存储的哈希,如VARCHAR(255)TEXT.

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

SELECT * FROM `users`;
Run Code Online (Sandbox Code Playgroud)

可以哈希到 $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']));
Run Code Online (Sandbox Code Playgroud)

结果:

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
Run Code Online (Sandbox Code Playgroud)

当我们发送这些内容时会发生什么password_hash()?它们都被散列,就像上面的查询一样.当您尝试验证密码时,会出现此问题.如果我们采用这些方法中的一种或多种,​​我们必须在比较它们之前重新使用它们password_verify().以下将失败:

password_verify($_POST['upassword'], $hashed_password); // where $hashed_password comes from a database query
Run Code Online (Sandbox Code Playgroud)

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


使用小于5.5的PHP版本?您可以使用password_hash() 兼容包.

你真的不应该使用MD5密码哈希.

  • 这就是为什么大多数事情要求您输入两次所选密码的原因.如果用户在事故中添加了空格,他们会在进一步了解之前将其弄清楚.如果用户故意这样做而不是非问题. (16认同)
  • 不可以.如果他使用尾随空格创建了他的密码,那么他必须在登录@DanBracuk时使用它们 (12认同)
  • 怎么这么@DanBracuk?如果我们允许用户设置他/她想要的密码,包括前导/尾随空格? (12认同)
  • @MargaretBloom,一条经验法则只是一种启发式方法.我们有时仍需要考虑事情,比如密码.你说"没人知道将来会发生什么变化",但似乎任何事情都会改变它是我们在将数据放入数据库之前逃避数据的方式,在这种情况下,当用户的密码没有时,用户会发现自己被锁定了更长时间匹配我们存储的内容.没有逃避密码哈希与逃避密码哈希的危险有什么危险? (4认同)
  • 确切地说:你当然会在有限的意义上"逃避哈希",正确地将它传递给参数化的SQL查询,其中SQL连接器中的某些代码可能会或可能不会对应于"转义","你不要"知道也不在乎.您不必编写任何特定的代码来实现这一点,因为除非您以前做过一些糟糕的人生决定,否则它对您的所有SQL查询都是完全常规的. (3认同)
  • 我并没有真正理解问题的全部内容。经验法则是清理业务所需的内容并“逃逸数据库中的所有内容” **。期。您必须逃避哈希,没人知道将来情况会如何变化。关于密码清除,这是一个热门话题。以Google为例[修改密码](https://support.google.com/accounts/answer/41078?hl=zh-CN),我个人不喜欢它。但是它的帮助中心肯定比我更能处理愤怒的用户。 (2认同)
  • PHP世界正试图通过经验丰富的语句来处理经验,但是旧的数据库API在野外广泛传播并且促进了坏习惯@DavidS (2认同)

leg*_*cia 35

在对密码进行散列之前,您应该按照RFC 7613的第4节中的描述对其进行标准化.特别是:

  1. 附加映射规则:任何非ASCII空间的实例必须映射到ASCII空间(U + 0020); 非ASCII空间是具有Unicode常规类别"Z"的任何Unicode代码点(U + 0020除外).

和:

  1. 规范化规则:Unicode规范化表格C(NFC)必须应用于所有字符.

这会尝试确保如果用户键入相同的密码但使用不同的输入法,则仍应接受密码.

  • @JayBlanchard因为当您按下一台机器上的空格键并在另一台机器上按下它时,您可能会获得两个不同的Unicode代码点,并且它们将具有两种不同的UTF-8编码,而无需用户知道任何内容.有人可能会认为这是一个你想忽略的问题,但RFC 7613是出于这样的现实问题,它不是一个制作工作的推荐. (4认同)
  • @DavidS,一个超级闪亮的北美Mac Book(Joe在离开之前使用)和一个国际化程度很低的台湾网吧电脑(Joe试图用来下载的是回程登机牌). (3认同)
  • 嗯.如果这样做,那么您还应该验证密码以拒绝任何包含尚未分配的字符的密码.如果用户使用NEWFANGLED SPACE,你的应用程序无法识别并因此散列原样,那将是非常糟糕的,然后你升级你的Unicode字符数据库,突然NEWFANGLED SPACE在散列之前被映射到SPACE,这样他(s)他无法输入您的应用将散列到旧哈希的密码. (3认同)
  • 听起来很神奇.:-)谢谢. (2认同)