跳到内容

如何保密敏感信息

编辑此页

环境变量是存储依赖于应用运行位置的配置的最佳方式 - 例如,在本地开发时可能设置为一个值,而在生产环境设置为另一个值的 API 密钥。

当这些值是敏感的且需要保密时,您可以使用 Symfony 的密钥管理系统(有时称为“保险库”)安全地存储它们。

注意

密钥系统需要 Sodium PHP 扩展。

生成加密密钥

为了加密和解密密钥,Symfony 需要加密密钥。可以通过运行以下命令生成密钥对

1
$ php bin/console secrets:generate-keys

这将生成一对非对称加密密钥。每个环境都有自己的一组密钥。假设您在 dev 环境中进行本地编码,这将创建

config/secrets/dev/dev.encrypt.public.php
用于加密/添加密钥到保险库。可以安全提交。
config/secrets/dev/dev.decrypt.private.php
用于解密/从保险库读取密钥。dev 解密密钥可以提交(假设 dev 保险库中没有存储高度敏感的密钥),但 prod 解密密钥绝不应该提交。

您可以通过运行以下命令为 prod 环境生成一对加密密钥

1
$ APP_RUNTIME_ENV=prod php bin/console secrets:generate-keys

这将生成 config/secrets/prod/prod.encrypt.public.phpconfig/secrets/prod/prod.decrypt.private.php

危险

prod.decrypt.private.php 文件高度敏感。您的开发团队甚至持续集成服务都不需要该密钥。如果解密密钥已泄露(例如,前雇员离职),您应该考虑通过运行以下命令生成新的密钥:secrets:generate-keys --rotate

创建或更新密钥

假设您想将数据库密码存储为密钥。通过使用 secrets:set 命令,您应该将此密钥添加到 dev prod 保险库中

1
2
3
4
5
6
7
# the input is hidden as you type for security reasons

# set your default development value (can be overridden locally)
$ php bin/console secrets:set DATABASE_PASSWORD

# set your production value
$ APP_RUNTIME_ENV=prod php bin/console secrets:set DATABASE_PASSWORD

这将在 config/secrets/dev 中创建一个新的密钥文件,并在 config/secrets/prod 中创建另一个文件。您还可以通过其他几种方式设置密钥

1
2
3
4
5
6
7
8
# provide a file where to read the secret from
$ php bin/console secrets:set DATABASE_PASSWORD ~/Download/password.json

# or contents passed to STDIN
$ echo -n "$DB_PASS" | php bin/console secrets:set DATABASE_PASSWORD -

# or let Symfony generate a random value for you
$ php bin/console secrets:set REMEMBER_ME --random

注意

没有命令可以重命名密钥,因此您需要创建一个新密钥并删除旧密钥。

在配置文件中引用密钥

密钥值可以像环境变量一样被引用。请注意,不要意外地定义一个密钥一个同名的环境变量:环境变量会覆盖密钥

如果您存储了一个 DATABASE_PASSWORD 密钥,您可以通过以下方式引用它

1
2
3
4
5
6
# config/packages/doctrine.yaml
doctrine:
    dbal:
        password: '%env(DATABASE_PASSWORD)%'
        # ...
    # ...

实际值将在运行时解析:容器编译和缓存预热不需要解密密钥

列出现有密钥

每个人都可以使用 secrets:list 命令列出密钥名称。如果您有解密密钥,您还可以通过传递 --reveal 选项来显示密钥的值

1
2
3
4
5
6
7
$ php bin/console secrets:list --reveal

 ------------------- ------------ -------------
  Name                Value        Local Value
 ------------------- ------------ -------------
  DATABASE_PASSWORD   "my secret"
 ------------------- ------------ -------------

显示现有密钥

如果您有解密密钥,则 secrets:reveal 命令允许您显示单个密钥的值。

1
2
3
$ php bin/console secrets:reveal DATABASE_PASSWORD

 my secret

7.1

secrets:reveal 命令在 Symfony 7.1 中引入。

移除密钥

Symfony 提供了一个方便的命令来移除密钥

1
$ php bin/console secrets:remove DATABASE_PASSWORD

本地密钥:在本地覆盖密钥

dev 环境密钥应包含用于开发的良好默认值。但有时开发人员在开发时仍然需要在本地覆盖密钥值。

大多数 secrets 命令(包括 secrets:set)都有一个 --local 选项,该选项将“密钥”存储在 .env.{env}.local 文件中,作为标准环境变量。要在本地覆盖 DATABASE_PASSWORD 密钥,请运行

1
$ php bin/console secrets:set DATABASE_PASSWORD --local

如果您输入 root,您现在将在 .env.dev.local 文件中看到这个

1
DATABASE_PASSWORD=root

这将覆盖 DATABASE_PASSWORD 密钥,因为环境变量始终优先于密钥。

列出密钥现在也将显示本地变量

1
2
3
4
5
6
$ php bin/console secrets:list --reveal
 ------------------- ------------- -------------
  Name                Value         Local Value
 ------------------- ------------- -------------
  DATABASE_PASSWORD   "dev value"   "root"
 ------------------- ------------- -------------

Symfony 还提供了 secrets:decrypt-to-local 命令,该命令解密所有密钥并将它们存储在本地保险库中,以及 secrets:encrypt-from-local 命令,该命令将所有本地密钥加密到保险库。

测试环境中的密钥

如果您在 devprod 环境中添加密钥,则它将从 test 环境中丢失。您可以为 test 环境创建一个“保险库”并在那里定义密钥。但更简单的方法是通过 .env.test 文件设置测试值

1
2
# .env.test
DATABASE_PASSWORD="testing"

将密钥部署到生产环境

由于解密密钥永远不应该被提交,您需要手动将此文件存储在某处并部署它。有两种方法可以做到这一点

  1. 上传文件

    第一个选项是将生产环境解密密钥 - config/secrets/prod/prod.decrypt.private.php 复制到您的服务器。

  2. 使用环境变量

    第二种方法是将 SYMFONY_DECRYPTION_SECRET 环境变量设置为生产环境解密密钥的 base64 编码值。获取密钥值的巧妙方法是

    1
    2
    3
    # this command only gets the value of the key; you must also set an env var
    # in your system with this value (e.g. `export SYMFONY_DECRYPTION_SECRET=...`)
    $ php -r 'echo base64_encode(require "config/secrets/prod/prod.decrypt.private.php");'

    为了提高性能(即避免在运行时解密密钥),您可以在部署期间将密钥解密到“本地”保险库

    1
    $ APP_RUNTIME_ENV=prod php bin/console secrets:decrypt-to-local --force

    这会将所有解密的密钥写入 .env.prod.local 文件。完成此操作后,解密密钥需要保留在服务器上。

轮换密钥

secrets:generate-keys 命令提供 --rotate 选项来重新生成加密密钥。Symfony 将使用旧密钥解密现有密钥,生成新的加密密钥,并使用新密钥重新加密密钥。为了解密以前的密钥,开发人员必须拥有解密密钥

配置

密钥系统默认启用,其某些行为可以配置

1
2
3
4
5
6
# config/packages/framework.yaml
framework:
    secrets:
        #vault_directory: '%kernel.project_dir%/config/secrets/%kernel.environment%'
        #local_dotenv_file: '%kernel.project_dir%/.env.%kernel.environment%.local'
        #decryption_env_var: 'base64:default::SYMFONY_DECRYPTION_SECRET'
本作品,包括代码示例,根据 Creative Commons BY-SA 3.0 许可获得许可。
目录
    版本