栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

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

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

前言

从表定义开始:

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

更改如下:

  1. 的字段
    Fname
    Lname
    Email
    将使用对称密码,通过提供待加密的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中,请考虑使用

BINARY
VARBINARY
列。如果这不是一个选项,则还可以使用
base64_enpre()
或将二进制数据转换为文本表示形式
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_depre($row['Name']);// $enc_name = hex2bin($row['Name']);$enc_name = $row['Name'];// $iv = base64_depre($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_enpre($random), '+', '.'), 0, 22));$hash = crypt($password, $salt);

生成盐

openssl_random_pseudo_bytes()
以形成随机数据块,然后遍历
base64_enpre()
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 comparefunction 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}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/433117.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号