Codeigniter加密类产生不一致的结果

时间:2013-10-12 15:32:24

标签: codeigniter encryption

我正在测试codeigniter加密库,似乎无法获得一致的结果。 我设置了一个测试页面,基本上只有以下代码

    $pwd = "test string";
    $key = "testkey_obviously_it_will_be_more_secure";
    for ($i=0; $i<11; $i++){
        echo $this->encrypt->encode($pwd, $key)."<br>";
    }

输出是10个完全不同的字符行。

我显然做错了什么,但我看不出它可能是什么。我尝试使用带有和没有$ key的编码功能,但结果对我来说是一样的。

顺便说一下,我在我的测试环境中使用codeigniter 2.1.0

1 个答案:

答案 0 :(得分:3)

编码库按预期工作。我们来看看默认的mcrypt_encode()方法:

function mcrypt_encode($data, $key)
{
        $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
        $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
        return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key);
}

请注意编码内发生的随机因素,并将噪声添加到加密中。尝试将您生成的10个密钥存储到一个数组中并对其进行解密。你会正确地恢复你的价值。

如果您正在寻找严格单向编码并产生一致的结果,我建议在PHP中使用hash()方法(从5.1.2开始提供):http://www.php.net/manual/ro/function.hash.php

生成哈希值的一种安全方法是创建一个随机种子值,然后将其连接到用户的密码。这可以防御彩虹表破解和其他事情。

hash('sha512', $seed . $password);

更新:我们的想法是使用加密类以便能够对某些字符串进行编码并还解码。可以这样想想 - 它不是一个安全的例子,但它可以帮助理解这一点:你想在你的网站上存储一个人的信用卡信息。当然,您希望保持这些信息的安全,这样如果有人闯入您的数据库,这并不是一件大事,因为所有这些信息都是加密的。您当然也希望能够解码该信息并将其显示给用户,以防他们再次从您的网站订购某些内容,而不是让他们手动输入数据,因此您还需要能够解密该数据。

一般来说,根据经验,我的理解是,如果加密算法是双向的(也就是说,它可以被编码和解码),那么它就不如单向加密算法那么安全(只编码数据)。

如果您正在存储用户登录凭据,您将永远不希望能够解码用户的密码,例如,因为这是用户可以轻松重置的内容。您永远不想在帐户上显示用户密码,因此您始终将其牢牢锁定。这是您使用单向加密算法的地方 - 您在创建条目时对数据进行一次编码,然后在数据库中查找条目时,而不是运行以下内容:

SELECT *
FROM user
WHERE user.password = 'STAR_WARS'

您可以运行类似:

SELECT *
FROM user
WHERE user.password = '5badcaf789d3d1d09794d8f021f40f0e'

上述方法可以通过编码您第一次从用户那里收到的数据进行编码,当您设置帐户时,然后无论何时检查登录凭据,您只需运行编码算法他们提供的字符串。

作为创建新帐户的工作流程:

  1. 用户使用密码'starwars'创建一个新帐户。
  2. 用户使用密码“5badcaf789d3d1d09794d8f021f40f0e”保存在数据库中,该密码是通过对用户提供的密码运行md5()获得的。
  3. 验证用户的工作流程:

    1. 用户通过登录表单发送密码'starwars'。
    2. 密码编码为'5badcaf789d3d1d09794d8f021f40f0e'。
    3. 我们检查数据库条目的密码为“5badcaf789d3d1d09794d8f021f40f0e”。
    4. 在上述系统中,我们从不存储用户的原始密码 - 仅存储加密数据。

      现在这本身看起来很简单,但是作为加密算法的MD5已经完全破解 - 也就是说,因为只有很多字符串组合可能,大多数值都被反转,所以黑客取值'5badcaf789d3d1d09794d8f021f40f0e '并且他们通过一个脚本运行它,列出可能的登录密码,这些密码都映射到'5badcaf789d3d1d09794d8f021f40f0e',其中我们也会找到'starwars'。

      重要的是让密码生成尽可能长或模糊,但尽可能随机。这就是为什么在上面的例子中,我们生成一个种子,我们用它来为密码添加一个随机元素,我们使用更强大的加密算法。

      所以种子可能是字符串:'sajuh27ahjs'。

      当用户创建新帐户时,我们会将种子与其原始密码连接起来。因此,对于我们的星球大战示例,用户在加密之前的原始密码将是:

      'sajuh27ahjsstarwars'
      

      种子存储在数据库中,没有加密,很明显,因为我们稍后需要解码。好的,现在我们用强大的东西加密密码,比如SHA512。因此我们得到:

      hash('sha512', $seed . $password);
      

      注意这种攻击很难打破,因为种子添加了一个随机元素,这使得破坏者很难理解我们放置种子的位置,即使有了这些知识,也需要建立一个表格。可以生成的每个特定随机种子的值映射(很多)。

      希望清除一些东西,随意拍出更多问题!