ps能看到密码是因为mongodb命令行启动时明文密码会留在/proc/pid/cmdline中;日志泄露则因程序可能将原始参数写入systemlog。有效防护是禁用命令行传密,改用配置文件或安全环境变量,并确保初始化脚本不含明文密码。

为什么 ps 能看到密码,而日志里也可能泄露?
因为 MongoDB 启动时若用命令行传参(比如 mongod --bind_ip 0.0.0.0 --port 27017 --auth --keyFile /path/key --replSet rs0),只要参数里带了明文密码(如 --password mypass123 或通过环境变量拼接进启动命令),这些字符串就会完整留在进程的 /proc/<pid>/cmdline</pid> 中——ps、top、容器 docker inspect 甚至某些日志采集器(如 filebeat 抓 stdout 前的原始启动行)都可能照单全收。
真正有效的隐藏方式:别让密码进命令行
MongoDB 官方明确不推荐在命令行中传密码。所有敏感字段必须走配置文件或环境变量(且环境变量本身不能出现在启动命令里)。
-
mongod支持--config <file></file>,把security.keyFile、replication.replSetName等写进 YAML/INI 文件,完全避开命令行 - 使用
MONGO_INITDB_ROOT_PASSWORD等 Docker 环境变量时,确保它只用于初始化,且容器启动命令里不 echo 或拼接该变量到mongod参数中(常见错误:写个 shell 脚本做mongod ... --password $MONGO_INITDB_ROOT_PASSWORD) - 如果必须用脚本动态构造命令,先用
unset MONGO_INITDB_ROOT_PASSWORD清掉变量,再执行mongod,否则 bash 历史和ps都可能残留
代码级擦除:仅限自研二进制或 fork 场景
像你提到的“把 argv[i+1] 全改成 x”这种技巧,本质是修改进程自己的 argv 内存空间,在 C/C++ 入口处生效。但它对 MongoDB 官方二进制无效——你没法改 mongod 的源码并重编译。
- 该手法只适用于你自己写的 C 程序,或基于 MongoDB 源码二次开发的定制版
- 即使做了,也只影响
ps输出,不影响日志:如果程序自己把原始argv打进了systemLog.path,照样白搭 - 注意
argv修改后,后续逻辑若还依赖原值(比如解析密码做校验),会直接失败
Docker 场景下最容易被忽略的泄漏点
很多人以为用了 volumes 映射 mongo-init.js 就安全了,但忘了检查两件事:
-
mongo-init.js文件本身不能含明文密码——比如写db.createUser({user:"admin", pwd:"123456"}),该文件若被误传到 Git 或被挂载进其他容器,就全暴露了 -
docker-compose.yml里如果用command:覆盖默认启动,并在里面拼接密码(如command: ["mongod", "--password", "${MONGO_PASS}"]),Env 替换后仍会出现在docker inspect的Args字段中 - 务必确认
mongo-init.js权限是644且无执行位(chmod -x),否则某些旧版 entrypoint 脚本可能误执行它并打印出错信息到日志
最省心的做法:初始化用 root 用户 + MONGO_INITDB_ROOT_* 环境变量,业务用户密码全部通过 db.changeUserPassword() 在连接后动态设置,全程不碰命令行和初始化脚本里的明文。











