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

2024-04-10

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

这就是我想做的:

我有一个由这些字段组成的表(用户 ID、姓名、姓名、电子邮件、密码)

我想要的是对所有字段进行加密然后解密(是否可以使用sha256用于加密/解密,如果没有任何加密算法)

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


Foreword

从表定义开始:

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

以下是变化:

  1. 田野Fname, Lname and Email将使用对称密码进行加密,由以下提供OpenSSL http://php.net/openssl,
  2. The IV字段将存储初始化向量 http://en.wikipedia.org/wiki/Initialization_vector用于加密。存储要求取决于所使用的密码和模式;稍后会详细介绍这一点。
  3. The Password字段将使用散列one-way密码哈希,

加密

密码和模式

选择最佳加密密码和模式超出了本答案的范围,但最终选择会影响加密密钥和初始化向量的大小;在这篇文章中,我们将使用 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);

Example

让我们使用之前的方法对名称字段进行加密$encryption_key and $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 or VARBINARY.

输出值与 IV 一样,是二进制的;要将这些值存储在 MySQL 中,请考虑使用BINARY or VARBINARY http://dev.mysql.com/doc/refman/5.0/en/binary-varbinary.html列。如果这不是一个选项,您还可以使用以下命令将二进制数据转换为文本表示形式:base64_encode() http://php.net/base64_encode or bin2hex() http://php.net/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
));

认证加密

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

Example

// 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
}

也可以看看:hash_equals() http://php.net/hash_equals

Hashing

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

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

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() http://php.net/openssl_random_pseudo_bytes形成一个随机的数据块,然后运行该数据块base64_encode() and strtr()匹配所需的字母表[A-Za-z0-9/.].

The crypt() http://php.net/crypt函数根据算法执行散列($2y$对于 Blowfish)、成本因子(在 3GHz 机器上,因子 13 大约需要 0.40 秒)和 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()再次,但您将之前计算的哈希值作为盐值传递。如果给定的密码与哈希值匹配,则返回值将产生相同的哈希值。为了验证哈希值,通常建议使用恒定时间比较函数以避免定时攻击。

使用 PHP 5.5 进行密码哈希处理

PHP 5.5 引入了密码散列函数 http://www.php.net/manual/en/ref.password.php您可以使用它来简化上述哈希方法:

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

并验证:

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

也可以看看:password_hash() http://php.net/password_hash, password_verify() http://php.net/password_verify

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在php中加密/解密数据? 的相关文章

  • 使用先前的反向引用作为命名捕获组的名称

    有没有办法使用对先前捕获组的反向引用作为捕获组的名称命名捕获组 这可能不可能 如果不可能 那么这就是一个有效的答案 下列 data description some description preg match data matches p
  • 如何在 PHP 中使用 cURL 发出同时包含 GET 和 POST 参数的请求?

    其他人已经问过如何从 perl java bash 等执行此操作 但我需要在 PHP 中执行此操作 并且我没有看到任何已提出的专门与 PHP 相关的问题 或包含 PHP 的答案 My code ch curl init url curl s
  • PHP:读取字体文件的 TrueType/OpenType 元数据

    如何阅读字体详细信息 例如 字体在其元数据中包含版权 姓氏 设计者 版本等信息 我还希望脚本能够计算文件中的字形数量 并返回字体支持的语言 例如 典型的字体可能包含西方语言 瑞典语和罗马语言支持 并具有数百个字形 它应该支持 truetyp
  • 语法错误,第 288 行出现意外的“endif”(T_ENDIF)[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我一直在离线处理我的 WordPress 网站的此代码错误 解析错误 语法错误 homez 541 photoher marie
  • Python PAM 模块的安全问题?

    我有兴趣编写一个 PAM 模块 该模块将利用流行的 Unix 登录身份验证机制 我过去的大部分编程经验都是使用 Python 进行的 并且我正在交互的系统已经有一个 Python API 我用谷歌搜索发现pam python http pa
  • 使用 XSLT 将 XML 转换为 SQL

    由于我无法控制的原因 我将获得一个 XML 文件和一个 XSLT 文件 该文件可以将 XML 文件转换为 SQL 代码或错误 现在让我们假设我们可以信任提供 XML 文件的人不会在 XML 中包含危险的构造 我什至不知道是否应该使用 Sim
  • postgreSql 中特定时间后表更新

    我已经在 postgres 中创建了表 现在我想在特定时间 例如 1 小时 后更新一行 我看到很多问题 例如 https dba stackexchange com questions 56424 column auto updated a
  • WordPress 插件中的类自动加载器

    我想编写一个类自动加载器以在 WordPress 插件中使用 该插件将安装在多个站点上 我想尽量减少与其他插件发生冲突的机会 自动加载器将是这样的 function autoload name some code here 我的主要问题是
  • 从支付网关重定向回时用户会话丢失

    我已将 Cyber source 配置为我的支付网关 我能够导航到 cybersource 并进行付款 并能够成功重定向回该网站 我也可以取消付款并重定向回我的网站 我收到来自支付网关的响应 但是 用户在从支付网关重定向回来时会被注销 我正
  • Laravel leftJoin 仅右表的最后一条记录

    我是 Laravel 的新手 我有两张桌子 1 产品 2 价格 products id product int p key name varchar prices id price int p key id product int
  • 如何使用 PHP 对字符串进行 rot13 处理?

    我有一个很大的 php 代码 我想手动对其进行编码和解码 我的问题是 php 代码里面有很多单引号和双引号 因此我在使用时出现错误str rot13 功能如下 那么正确的语法是什么以及如何使用下面的函数进行编码 str rot13 That
  • 从 PHP 数组生成 HTML 表

    我不明白这一点 我需要解决看似简单的问题 但这超出了我的逻辑 我需要编写一个函数 table columns input cols 它将输出一个表 示例 input array apple orange monkey potato chee
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • 如何在laravel中注册后自动登录

    我在 laravel 中注册用户时遇到问题 user假设是包含所有数组元素的数组 同时自动登录以下代码结果false 数据库中保存的密码是hash make password user id this gt user model gt ad
  • 为什么我的会话仍然存在?

    我一定很愚蠢 因为似乎一件相当明显的事情现在让我完全困惑 我有一个会议 ie SESSION handbag id 在某个时刻 我需要彻底终止这个会话 ie at the start of the page session start el
  • 免费 PHP 登录库 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • PHP 通过 SSL 连接到 MS SQL

    我想要实现的目标非常简单 我想通过安全连接从 PHP 脚本连接到外部 MS SQL 数据库 然而 这已被证明是有问题的 到目前为止 经过三个小时的研究 我不知所措 客户端的平台是Ubuntu 这意味着我无法使用SQLSRV 安全连接已经在不
  • 将 PHP 短开放标签替换为

    我有大量多年来编写的 php 文件 我需要将所有短开放标签正确替换为正确的显式开放标签 change
  • JSEncrypt 在后端解密(Bash)

    看起来 JSEncrypt 在 RSA 加密字符串中添加了一些随机填充 因此我无法使用 OpenSSL 对其进行解密 我的 JS 代码如下所示 const rsaEncrypt new window JSEncrypt rsaEncrypt
  • Android - 在sqlite数据库中存储敏感数据

    我需要将敏感数据存储在 Android 应用程序的 sqlite 数据库中 我如何确定这些数据非常安全 我知道我可以使用密钥加密数据 但是我将该密钥存储在哪里 我也不想要求用户填写密钥 我只是希望它能够自行工作 因为我害怕逆向工程 所以我也

随机推荐