如何保密敏感信息
环境变量是存储依赖于应用运行位置的配置的最佳方式 - 例如,在本地开发时可能设置为一个值,而在生产环境设置为另一个值的 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.php
和 config/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 中引入。
本地密钥:在本地覆盖密钥
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
命令,该命令将所有本地密钥加密到保险库。
测试环境中的密钥
如果您在 dev
和 prod
环境中添加密钥,则它将从 test
环境中丢失。您可以为 test
环境创建一个“保险库”并在那里定义密钥。但更简单的方法是通过 .env.test
文件设置测试值
1 2
# .env.test
DATABASE_PASSWORD="testing"
将密钥部署到生产环境
由于解密密钥永远不应该被提交,您需要手动将此文件存储在某处并部署它。有两种方法可以做到这一点
上传文件
第一个选项是将生产环境解密密钥 -
config/secrets/prod/prod.decrypt.private.php
复制到您的服务器。使用环境变量
第二种方法是将
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'