2

我正在测试 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 的 encode 函数,但结果对我来说是一样的。

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

4

1 回答 1

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() 获得的。

验证用户的工作流程:

  1. 用户通过登录表单发送密码“starwars”。
  2. 密码编码为“5badcaf789d3d1d09794d8f021f40f0e”。
  3. 我们检查我们的数据库条目,其中的密码是“5badcaf789d3d1d09794d8f021f40f0e”。

在上面的系统中,我们从不存储用户的原始密码——只存储加密数据。

现在这本身看起来很简单,但是MD5作为一种加密算法已经被完全破解了——也就是说,因为可能的字符串组合只有这么多,大部分值都被颠倒了,所以黑客取了值'5badcaf789d3d1d09794d8f021f40f0e'然后他们通过列出可能的登录密码的脚本运行它,这些密码都映射到“5badcaf789d3d1d09794d8f021f40f0e”,其中我们还会找到“星球大战”。

重要的是不要让您的密码生成尽可能长或模糊,而是尽可能随机。这就是为什么在上面的示例中,我们生成了一个种子,用于向密码添加随机元素,并且我们使用了更强大的加密算法。

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

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

'sajuh27ahjsstarwars'

种子存储在数据库中,没有加密,一目了然,因为我们稍后需要它来解码。好的,现在我们用强的东西加密密码,比如 SHA512。因此我们得到:

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

请注意这种攻击是如何很难破解的,因为种子添加了一个随机元素,这使得破解者很难理解我们将种子放在哪里,即使有了这些知识,它也需要构建一个值映射表可以生成的每个特定随机种子(很多)。

希望能解决一些问题,否则请随时提出更多问题!

于 2013-10-12T15:43:14.797 回答