PHP 如何在没有硬编码密钥的情况下进行对称加密

How to do symmetric cryptography without hardcoded key in PHP

我正在使用 PHP mcrypt 库使用 AES 加密和存储 (MySQL) 数据。

我想知道是否有一种好的方法可以在我的代码中没有硬编码 encryption/decryption 键的情况下执行此操作。

如果黑客可以访问我的服务器,他将能够看到代码中的文件和我的密钥,从而访问数据库中的所有数据。

谢谢。

这取决于你愿意走多远,以及你的环境。

将解密密钥保存在数据库中绝对不是一个好主意 - 如果有人获得了数据库,他们将同时拥有解密密钥和数据。通过将其存储在应用服务器上,您可以确定不会发生上述情况。但是,如果有人访问了应用服务器,然后通过应用服务器访问了数据库怎么办?现在他们又拥有了密钥和数据。但是你已经说了这么多了。

由于您没有提及您的环境,我们假设:

  • 标准LAMP堆栈
  • PHP 作为 Apache 模块运行
  • 你有一个部署tool/script来部署你的应用程序

您可以拥有一个简单的 Apache 配置文件:

  • 将环境变量设置为您的加密密钥的值
  • 从主 Apache 配置中包含
  • 加密存储在 disk/repo/wherever 您的部署工具可以访问

然后在部署期间:

  • 作为其部署步骤的一部分,您的部署工具会尝试解密加密的配置文件并向部署用户询问密钥
  • 部署用户提供来自 system/method 完全未连接到 运行 生产应用程序的密钥(例如离线安全密码存储等)
  • 部署工具将文件复制到生产系统并解密
  • 部署工具在生产系统上(重新)启动 Apache
  • Apache加载解密后的配置文件,设置环境变量
  • 一旦 Apache 成为 运行,部署工具 deletes/overwrites/shreds/etc。包含安全加密密钥的解密配置文件

在此之后,当前的状态将是:

  • Apache 已将配置加载到内存中,解密密钥可通过环境变量PHP使用
  • 安全密钥未存储在生产系统的任何位置,它仅在内存中可用
  • 您可以 reload/restart Apache 的唯一方法是通过您的部署工具(无论如何这可能是您想要的)

你怎么可能仍然容易受到攻击:

  • 当您在受支持的文件系统上直接写入磁性硬盘驱动器时,粉碎文件是安全的;它在 VM 或 SSD 环境中可能不那么安全
  • 有权访问应用程序服务器的攻击者可以转储 Apache 使用的内存并尝试弄清楚如何获取那里某处的解密密钥
  • 在部署期间的几秒钟内,当 Apache 加载时,服务器上的文件未加密;如果攻击者有不间断的访问权限并且知道要查找什么,他们可能会幸运地找到该文件

不过,它比将未加密的密钥存储在应用程序服务器上要安全得多,而且它需要非常复杂和高度老练的攻击者才能利用。所以,正如我一开始所说的,这取决于你想走多远。

I'm using the PHP mcrypt library to cryptograph and store (MySQL) data using AES.

You may wish to reconsider your choice in cryptography library.

I was wondering if there is a good way to do this without having a hardcoded encryption/decryption key in my code.

将其存储在文档根目录之外的配置文件中?例如,defuse/php-encryption

If a hacker gets access to my server he will be able to see the files and my key on the code, therefore accessing all the data on the database.

如果黑客可以访问您的服务器,symmetric-key encryption cannot save you。但是,Public-密钥加密可以保密。

使用Halite,这很容易解决:

  1. 只能在服务器上加密;永不解密。
  2. 您的密钥必须离线保存并由人使用。

在线代码(假设 PHP 7.0 和 Halite 2.1)

<?php
declare(strict_types=1);
use ParagonIE\Halite\{
    Asymmetric\Crypto as Asymmetric,
    KeyFactory
};

$publicKey = KeyFactory::loadEncryptionPublicKey("/path/to/public/key");
$encrypted = Asymmetric::seal("Whatever secret data we want", $publicKey);
// Now do whatever you need with $encrypted

离线代码(假设 PHP 7.0 和 Halite 2.1)

<?php
declare(strict_types=1);
use ParagonIE\Halite\{
    Asymmetric\Crypto as Asymmetric,
    KeyFactory
};

$salt = ""; // Generate from random_bytes(16) once, then persist.
$password = ""; // Create a strong password

$keyPair = KeyFactory::deriveEncryptionKeyPair($password, $salt);
$secretKey = $keyPair->getSecretKey();
$publicKey = $keyPair->getPublicKey();

// To have the public key to a file to upload to the server:
   KeyFactory::save($publicKey, '/path/to/public/key');

$decrypted = Asymmetric::unseal($encrypted, $secretKey);