2014-05-05 169 views
4

我有这个问题,请问如果不合适,请在评论中告诉我,我会放弃它。事情如下: 我生成盐与此代码:哈希密码并将其保存并将其保存到mysql pdo utf8编码

$salt = mcrypt_create_iv(32); 

,密码是这样的:

$password = hash('sha256', $_POST['password'] . $salt); 

和$盐和$密码保存到MySQL数据库,没有问题到目前为止,如果我连这样:

$pdo = new PDO(
    'mysql:host=hostname;dbname=defaultDbName', 
    'username', 
    'password' 
); 

但如果我这个其他方式连接

盐不会保存到数据库或保存错误的值和长度;除非我这样做: $ salt = utf8_encode(mcrypt_create_iv(32);); 但我认为这是不对的,我的意思是我为什么要编码,mcrypt_create_iv(32)和utf-8的问题是什么?

+0

你的IV本质上将是“随机的”二进制垃圾。如果您将它放入文本/ varchar字段,它将受到字段的字符集转换规则的约束。二进制数据应该进入varbinary/blob字段。这些都没有charsets,并且你投入的领域将是什么从它出来。 –

+0

因此,将字段的tipe改为blob将会使连接的字符集不可知,这就是您所说的 – Bloodraven

+0

这就是二进制/ blob字段的要点。由于翻译规则的不正确应用导致无法随机地垃圾数据,因此翻译规则永远无法应用于数据。 –

回答

4

您的解决方案将工作:

mcrypt_create_iv返回一串字节,这是方便放在一个字符串。但是因为它们可以具有任何价值,所以它们可能会导致UTF-8序列不正确。 utf8_encode修复了这个问题,并且只要您还记得在从数据库中读回数据库后使用utf8_decode,它将正常工作。

如果您的连接不是utf8,那么每个字节将被视为单个(全部)ANSI字符,并且您不需要任何编码即可。

最好的解决办法:保持二进制:

由于该数据实际上是不是一个真正的字符串,二进制领域二进制数据(BINARY,VARBINARY或BLOB)将是一个更好的选择,因为它存储到防止由于编码或解码造成的任何问题。

BINARY可能是最好的选择,因为这个数据的长度既不可变,也不大。

参见http://dev.mysql.com/doc/refman/5.0/en/binary-varbinary.html

备选:存储作为实际文字,而不花式字符:

另一种解决方案是使用bin2hex到二进制数据转换成十六进制表示。字符串的长度是原来的两倍,但它只包含字母和数字,并且对任何类型的字符串字段都是安全的。您可以使用hex2bin将其转换回来。

+0

好的,谢谢,我现在明白了,我还想问你是否没有关于使用utf-8编码的安全问题? – Bloodraven

+0

可能有。我会选择将这些信息以原始二进制格式保存在'BINARY'字段中。 – GolezTrol

0

正如其他海报所提到的,mcrypt_create_iv可以生成不符合utf8的字符。尝试是这样的:

function generate_random($length=16, $simple=false){ 
     $result=''; 
     $chars = '[email protected]#$%^&*()+=-_?~'; 
     if($simple) 
      $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'; 
     for ($i = 0; $i < $length; $i++) 
      $result .= $chars[mt_rand(0, strlen($chars)-1)]; 
     return $result; 
    } 

16个字符与字符集的78个产量1.877 * 10^30种组合。加上密码长度应该足够用于像sha256这样的单向散列。

+0

感谢您的回答,这看起来像DIY工作,如何称为您的编码方式没有括号? – Bloodraven

相关问题