当前位置: 首页 > 面试题库 >

如何在php中加密/解密数据?

子车桐
2023-03-14
问题内容

我目前是一名学生,并且正在学习PHP,我正在尝试对PHP中的数据进行简单的加密/解密。我进行了一些在线研究,其中一些非常令人困惑(至少对我而言)。

这是我想做的事情:

我有一个包含这些字段 (用户ID,Fname,Lname,Email,Password)的表

我要拥有的是先将所有字段加密,然后再解密(sha256如果没有任何加密算法,是否可以用于加密/解密)

我想学习的另一件事是如何创建一种hash(sha256)与优质“盐”结合的单一方法。(hash(sha256)+salt)
先生/女士,我基本上只是想一个简单的加密/解密实现,您的回答会很有帮助,非常感谢。谢谢++


问题答案:

从表定义开始:

- UserID
- Fname
- Lname
- Email
- Password
- IV

更改如下:

  1. 的字段FnameLnameEmail将使用对称密码,通过提供待加密的OpenSSL,
  2. IV字段将存储用于加密的初始化向量。存储要求取决于所使用的密码和模式。稍后再详细介绍。
  3. Password字段将使用 单向 密码哈希进行哈希处理,

加密

密码和方式

选择最佳的加密密码和模式超出了此答案的范围,但是最终的选择会影响加密密钥和初始化向量的大小;在本文中,我们将使用AES-256-CBC,它的固定块大小为16个字节,密钥大小为16、24或32个字节。

加密金钥

一个好的加密密钥是从可靠的随机数生成器生成的二进制Blob。建议使用以下示例(> = 5.3):

$key_size = 32; // 256 bits
$encryption_key = openssl_random_pseudo_bytes($key_size, $strong);
// $strong will be true if the key is crypto safe

可以执行一次或多次(如果您希望创建一串加密密钥)。尽可能将它们保密。

IV

初始化向量为CBC模式增加了加密的随机性。理想情况下,这些值只能使用一次(每个加密密钥技术上只能使用一次),因此,对行的任何部分进行更新都应重新生成它。

提供了一个功能来帮助您生成IV:

$iv_size = 16; // 128 bits
$iv = openssl_random_pseudo_bytes($iv_size, $strong);

让我们使用较早的$encryption_key和加密名称字段$iv。为此,我们必须将数据填充到块大小:

function pkcs7_pad($data, $size)
{
    $length = $size - strlen($data) % $size;
    return $data . str_repeat(chr($length), $length);
}

$name = 'Jack';
$enc_name = openssl_encrypt(
    pkcs7_pad($name, 16), // padded data
    'AES-256-CBC',        // cipher and mode
    $encryption_key,      // secret key
    0,                    // options (not used)
    $iv                   // initialisation vector
);

储存要求

像IV一样,加密输出是二进制的。可以通过使用指定的列类型(例如BINARY或)来将这些值存储在数据库中VARBINARY

与IV一样,输出值为二进制。要将这些值存储在MySQL中,请考虑使用BINARYVARBINARY列。如果这不是一个选项,则还可以使用base64_encode()或将二进制数据转换为文本表示形式bin2hex(),这样需要增加33%到100%的存储空间。

解密

存储值的解密类似:

function pkcs7_unpad($data)
{
    return substr($data, 0, -ord($data[strlen($data) - 1]));
}

$row = $result->fetch(PDO::FETCH_ASSOC); // read from database result
// $enc_name = base64_decode($row['Name']);
// $enc_name = hex2bin($row['Name']);
$enc_name = $row['Name'];
// $iv = base64_decode($row['IV']);
// $iv = hex2bin($row['IV']);
$iv = $row['IV'];

$name = pkcs7_unpad(openssl_decrypt(
    $enc_name,
    'AES-256-CBC',
    $encryption_key,
    0,
    $iv
));

认证加密

通过附加从秘密密钥(不同于加密密钥)和密文生成的签名,可以进一步提高所生成密文的完整性。在对密文进行解密之前,首先要验证签名(最好使用恒定时间比较方法)。

// generate once, keep safe
$auth_key = openssl_random_pseudo_bytes(32, $strong);

// authentication
$auth = hash_hmac('sha256', $enc_name, $auth_key, true);
$auth_enc_name = $auth . $enc_name;

// verification
$auth = substr($auth_enc_name, 0, 32);
$enc_name = substr($auth_enc_name, 32);
$actual_auth = hash_hmac('sha256', $enc_name, $auth_key, true);

if (hash_equals($auth, $actual_auth)) {
    // perform decryption
}

散列

必须尽可能避免在数据库中存储可逆密码。您只希望验证密码而不知道密码的内容。如果用户丢失了密码,最好让他们重设密码,而不是将其原始密码发送给他们(确保密码重设只能在有限的时间内完成)。

应用哈希函数是一种单向操作。之后,可以安全地用于验证,而无需透露原始数据;对于密码,暴力破解是发现密码的一种可行方法,因为密码的长度相对较短且许多人选择的密码不多。

制定了诸如MD5或SHA1之类的哈希算法,以针对已知哈希值验证文件内容。它们经过了极大的优化,可以使验证速度尽可能快,同时仍保持准确。由于它们的输出空间相对有限,因此很容易使用已知的密码及其各自的哈希输出(彩虹表)来构建数据库。

在对哈希值进行哈希运算之前,先在密码中添加盐,这将使彩虹表变得毫无用处,但是最近的硬件改进使蛮力查找成为一种可行的方法。这就是为什么您需要一种故意慢且根本无法优化的哈希算法。它还应该能够增加更快硬件的负载,而又不影响验证现有密码散列以使其成为未来的能力。

当前有两个流行的选择:

  1. PBKDF2(基于密码的密钥派生函数v2)
  2. bcrypt(又名河豚)

此答案将使用bcrypt的示例。

可以这样生成密码哈希:

$password = 'my password';
$random = openssl_random_pseudo_bytes(18);
$salt = sprintf('$2y$%02d$%s',
    13, // 2^n cost factor
    substr(strtr(base64_encode($random), '+', '.'), 0, 22)
);

$hash = crypt($password, $salt);

生成盐openssl_random_pseudo_bytes()以形成随机数据块,然后遍历base64_encode()strtr()匹配所需的字母[A-Za-z0-9/.]

crypt()函数根据算法($2y$针对Blowfish),成本因素(在3GHz的计算机上为13的因素花费大约0.40s)和22个字符的盐来执行哈希处理。

验证方式

一旦获取了包含用户信息的行,就可以通过以下方式验证密码:

$given_password = $_POST['password']; // the submitted password
$db_hash = $row['Password']; // field with the password hash

$given_hash = crypt($given_password, $db_hash);

if (isEqual($given_hash, $db_hash)) {
    // user password verified
}

// constant time string compare
function isEqual($str1, $str2)
{
    $n1 = strlen($str1);
    if (strlen($str2) != $n1) {
        return false;
    }
    for ($i = 0, $diff = 0; $i != $n1; ++$i) {
        $diff |= ord($str1[$i]) ^ ord($str2[$i]);
    }
    return !$diff;
}

要验证密码,请crypt()再次调用,但将先前计算的哈希值作为salt值传递。如果给定的密码与哈希匹配,则返回值将产生相同的哈希。为了验证哈希,通常建议使用恒定时间比较功能以避免定时攻击。

PHP 5.5的密码哈希

PHP 5.5引入了密码哈希函数,可用于简化上述哈希方法:

$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 13]);

并验证:

if (password_verify($given_password, $db_hash)) {
    // password valid
}


 类似资料:
  • 我有一个由以下字段组成的表(UserID、Fname、Lname、Email、Password) 我想要的是加密所有字段,然后解密(如果没有任何加密算法,是否可以使用进行加密/解密) 我想学的另一件事是如何创建一个单向的并结合一个好的“salt”。(基本上我只想有一个加密/解密的简单实现,先生/女士,您的回答将会有很大的帮助,非常感谢。谢谢++

  • 客户端(4.2.1)应用程序通过请求向(5.6)API发送公钥。此API使用符合的加密数据,然后使用OpenSSL public encryption和的客户端公钥加密AES加密的密钥。它将通过编码的数据发送回客户端android应用程序,客户端android应用程序将加密数据。我已经设置了一个基本的PHP测试脚本来测试整个过程,这是预期的工作。 目前,我正在客户端Android应用程序中实现解密

  • 本文向大家介绍PHP加密解密函数详解,包括了PHP加密解密函数详解的使用技巧和注意事项,需要的朋友参考一下 分享一个PHP加密解密的函数,此函数实现了对部分变量值的加密的功能。 加密代码如下: 解密代码如下: 辅助函数: 使用如下所示: 以上就是为大家分享的php加密解密函数,希望大家喜欢,可以应用到自己的学习中。

  • 我用java加密一个单词,但用php解密时遇到了问题。 以下是我如何在android中创建密钥: 下面是我如何在android中使用生成的公钥加密单词: 然后我在android中将加密字符串转换为Bas64: 在php中,我解码base64字符串: 获取私钥: 最后,我尝试用php解密这个字符串: 我得到的错误是: 警告:openssl_private_decrypt():密钥参数不是有效的私钥.

  • 本文向大家介绍如何在PHP中使用AES加密算法加密数据,包括了如何在PHP中使用AES加密算法加密数据的使用技巧和注意事项,需要的朋友参考一下 在研究Discuz 的时候,发现Discuz有一套相当完美的加密算法(相对而言)。这个算法可以将数据加密后,储存起来,到需要用的时候,用之前加密的秘钥将之还原。 除了这个之外,还有AES这个算法能够将数据很好的加密起来,在传输过程中不容易被破解。 在PHP

  • 问题内容: 我找到了在PHP中对字符串进行编码/解码的示例。起初它看起来非常好,但是不会起作用:-( 有人知道问题出在哪里吗? 结果是: 加密: 解密: 问题答案: 并且 在您的代码中未定义。查看有效的解决方案( 但不安全! ): 停! 这个例子是 不安全的! 不要使用它! **但是此代码中还有其他问题,使其变得不安全,尤其是使用ECB(这不是_加密_模式,只能在其上定义加密模式的构造块)。