应将phpmyadmin数据库凭据从config.inc.php中移出,存于web不可访问路径(如/etc/phpmyadmin/secrets.php),权限设为600,并通过include加载;认证模式必须设为'cookie',禁用allowarbitraryserver,mysql账号须按最小权限原则精确授权。
config.inc.php 里别硬编码密码
明文写在 config.inc.php 里的 $cfg['servers'][$i]['user'] 和 $cfg['servers'][$i]['password'],等于把钥匙贴在门上。哪怕 web 服务器配置了禁止直接访问该文件,一旦 php 解析失败、.php 后缀被绕过或备份文件泄露,密码就全暴露。
正确做法是把敏感字段抽离到 Web 服务器不可直接访问的路径(比如 /etc/phpmyadmin/secrets.php),再用 include 加载:
include('/etc/phpmyadmin/secrets.php');
/etc/phpmyadmin/secrets.php 内容示例(注意权限设为 600):
$secrets = [
'db1' => ['host' => '192.168.0.10', 'user' => 'pma_user', 'pass' => 'xK9#qL2!'],
'db2' => ['host' => '10.20.30.40', 'user' => 'pma_ro', 'pass' => 'vF7@mN5*'],
];
然后在 config.inc.php 中循环注入:
foreach ($secrets as $idx => $s) {
$i++;
$cfg['Servers'][$i]['host'] = $s['host'];
$cfg['Servers'][$i]['user'] = $s['user'];
$cfg['Servers'][$i]['password'] = $s['pass'];
$cfg['Servers'][$i]['auth_type'] = 'cookie';
}
- 确保
/etc/phpmyadmin/secrets.php不在 Web 根目录下,且 Apache/Nginx 配置中未将其映射为可访问路径 - PHP 进程需有读取该文件的权限,但普通用户不能
cat或ls到它 - 不要用
$_ENV或getenv()—— 多数共享主机不支持,且环境变量可能被phpinfo()泄露
用 cookie 模式替代 config 模式
$cfg['Servers'][$i]['auth_type'] = 'config' 是最危险的快捷方式:它让 phpMyAdmin 自动登录,但代价是密码必须明文存在配置里,且无法区分操作人身份。
生产环境唯一推荐的是 'cookie' 模式 —— 用户每次登录都要输账号密码,而这些凭据只存在于浏览器 Session 和服务端临时 Session 文件中,不落盘、不复用、可审计。
- 启用
'cookie'后,$cfg['Servers'][$i]['user']和$cfg['Servers'][$i]['password']字段可留空或删掉,它们会被忽略 - MySQL 侧对应用户必须已授权(如
'pma_user'@'192.168.0.100'),且密码由用户自己输入,不是 phpMyAdmin 代填 - 若想减少重复输入,可配合浏览器密码管理器,而不是靠配置文件“自动”
避免 $cfg['AllowArbitraryServer'] = true
这个开关一开,登录页就出现“服务器”输入框,允许用户任意填 IP 和账号连库 —— 看似灵活,实则等于开放 SQL 客户端入口给任何人,只要能访问 phpMyAdmin 页面。
它绕过了所有预定义的服务器白名单逻辑,也使你无法控制连接来源、无法审计谁连了哪台库、更无法限制权限粒度。
- 禁用它:
$cfg['AllowArbitraryServer'] = false;(默认值,别改) - 多服务器管理应走预定义方式(即上文循环加载
$secrets),每台库都显式声明、独立授权、单独审计 - 如果真需要动态输入,应在反向代理层(如 Nginx)做 IP 白名单 + HTTP Basic Auth 双重校验,而不是交给 phpMyAdmin 处理
MySQL 用户必须按最小权限原则授权
phpMyAdmin 连得上,不等于它该拥有全部权限。一个用于管理的账号,如果被爆破或 XSS 劫持,权限越大,破坏越猛。
不要用 GRANT ALL PRIVILEGES ON *.*,尤其别带 WITH GRANT OPTION。针对每个服务器,创建专用账号并限制范围:
- 只读账号:
GRANT SELECT, SHOW VIEW ON `app_db`.* TO 'pma_ro'@'192.168.0.100'; - 运维账号:
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON `app_db`.* TO 'pma_rw'@'192.168.0.100'; - 绝对禁止
GRANT ... ON *.*或mysql.*库的写权限 - Host 必须精确到 IP 或 CIDR(如
'192.168.0.100'),不用'%',除非网络隔离已做到位
真正难的不是写对配置,而是让每个环节都守住自己的边界:phpMyAdmin 不存密、不越权登录;MySQL 不放行宽泛账号;Web 服务器不暴露敏感路径。漏掉任一环,前面所有努力都归零。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











