数据库密码不应在database.php中明文存储或可逆加密,而应通过环境变量(如getenv('db_password'))运行时注入,或由外部隔离文件(chmod 600)提供,确保密钥与配置分离、权限可控、不入版本库。

database.php 里的数据库密码不能靠“加密存储”来解决安全问题——它本身就不该以可逆方式存在,更不该依赖框架的 Encryption 类去加解密。真正安全的做法是移出代码、交由运行时注入,否则无论你怎么套 encrypt() 或 base64_encode(),都只是制造虚假安全感。
database.php 不该存任何明文密码
你看到的 $db['default']['password'] = 'my-secret-pass'; 是最大风险点。这个文件可能被意外提交到 Git、被 Web 服务器错误配置导致源码泄露、或被共享给协作人员。CI 框架不提供“对配置项自动解密”的机制,硬塞进 encrypt() 反而会引入启动失败、密钥管理混乱、部署失败等新问题。
- 密码字段不是业务数据,不需要在运行时加解密
-
Encryption类依赖$config['encryption_key'],而该密钥又得写在同一个 config 目录下,等于锁门还把钥匙焊在门把手上 - CI 3.x 的
$this->encryption->encrypt()返回的是带 IV + HMAC 的完整二进制结构,直接赋值给password字段会导致连接失败(MySQL 认不出这种字符串)
正确思路是:让密码脱离 PHP 配置文件,由环境或容器注入。
用环境变量替代硬编码密码(推荐)
PHP 7.1+ 原生支持 getenv(),且 Apache/Nginx/CLI/Docker 均可安全传递:
$db['default']['password'] = getenv('DB_PASSWORD') ?: '';
- 开发时在 shell 中执行:
export DB_PASSWORD="dev-pass-2026" - 生产部署时,通过 systemd service 文件、Docker
--env-file、或云平台 Secret Manager 注入 - 不需要修改 CI 框架任何逻辑,零兼容性风险
注意两点:
- 确保
php.ini中variables_order包含E(即启用getenv) - 不要写成
getenv('DB_PASSWORD', true)—— 第二个参数是 PHP 8.1+ 才支持的,CI 3.x 项目大概率报错
如果必须用文件隔离,就用外部配置文件 + chmod 600
某些老旧运维流程不允许环境变量,可折中:
require_once '/etc/ci-secrets/database.php';$db['default']['password'] = $DB_PASSWORD ?? '';
- 该文件不在
application/目录下,不参与 Git 提交 - 设置权限:
sudo chmod 600 /etc/ci-secrets/database.php,确保只有 Web 用户可读 - 文件内容仅一行:
<?php $DB_PASSWORD = 'real-prod-pass-!2x';
别用 include() 动态路径拼接,也别尝试用 file_get_contents() 再 base64 解码——增加无谓复杂度,还容易因路径错误导致空密码静默连接失败。
别碰 encryption_key 和数据库密码混用
有人想复用 $config['encryption_key'] 去“保护”数据库密码,这是典型误用:
-
encryption_key专用于 Cookie 加密、Session 加密、Encryption类加解密,和数据库连接层无关 - 若你在
database.php里调用$this->encryption->decrypt(),会触发Fatal error: Using $this when not in object context—— 此时 CI 核心尚未加载,$this根本不存在 - 即使绕过,也会让每次数据库连接都多一次 OpenSSL 解密开销,毫无必要
真正该保护的,是 encryption_key 本身:它必须是 openssl_random_pseudo_bytes(32) 生成的二进制密钥,且一旦写死就不能改——这点比数据库密码重要得多。
密钥不可逆、环境不可信、配置不可见——这三条才是 CI 项目配置安全的底层逻辑。数据库密码不是拿来“加密”的,是拿来“隔离”的。漏掉权限控制、暴露在 Git、或塞进可读配置文件,比用不用 AES 严重得多。











