3、硬编码凭据的风险:源代码中的密码、配置文件中的密钥、环境变量中的Token
说实话,硬编码凭据这个问题,我在工厂里见过太多次了。每次做安全审计,翻开代码仓库或者配置文件,总能找到几个“惊喜”。
什么叫硬编码凭据?说白了,就是把密码、密钥、Token 这些敏感信息,直接写在源代码里、配置文件里,或者环境变量里。听起来很蠢对吧?但现实中,这几乎是每个工厂 IT/OT 项目都踩过的坑。
我自己就经历过一次。那是一个 MES 系统的升级项目,前任开发把数据库连接密码直接写在 Java 代码里。结果代码被一个实习生不小心 push 到了公开仓库。嗯,那天晚上我们整个团队都在改密码。
3.1 源代码中的密码:最直接的“裸奔”
先看源代码。这是最危险的一种硬编码方式。密码就躺在代码里,谁都能看到。
典型场景:
- 数据库连接字符串里直接写用户名和密码
- 调用第三方 API 时,在代码里写死 API Key
- PLC 或 SCADA 系统的通信密码硬编码在脚本中
举个例子,你可能会看到这样的代码:
// 千万别这么干!
String dbUrl = "jdbc:mysql://192.168.1.100:3306/mes_db";
String dbUser = "admin";
String dbPassword = "P@ssw0rd123!";
Connection conn = DriverManager.getConnection(dbUrl, dbUser, dbPassword);
为什么说这很危险?你想想看,代码要经过版本控制吧?Git、SVN 这些工具会记录每一次变更。密码一旦提交上去,就永远留在历史记录里了。哪怕你后来删掉了,有心人翻翻历史记录就能找到。
我在一个汽车零部件工厂就遇到过这种事。他们的 PLC 上位机软件里硬编码了 OPC 服务器的连接密码。后来有员工离职,带走了源代码。结果怎么样?整个车间的生产数据被人看了个遍。
⚠️ 核心风险:
- 版本控制历史会永久保留密码
- 代码审查时,所有能看到代码的人都能获取密码
- 一旦泄露,需要修改所有相关系统的密码,工作量巨大
3.2 配置文件中的密钥:看似隐蔽,实则脆弱
有些人觉得,把密码写在配置文件里总比写在代码里强吧?嗯,确实好一点,但也好不到哪去。
配置文件通常和代码一起打包、一起部署。常见的配置文件有 .properties、.yaml、.json、.xml 这些格式。密码就明晃晃地写在里面。
# application.properties
spring.datasource.url=jdbc:mysql://192.168.1.100:3306/mes_db
spring.datasource.username=admin
spring.datasource.password=P@ssw0rd123!
你可能会说:“我把配置文件放到 .gitignore 里不就行了?” 好问题。但现实是,很多人忘了加。或者项目初期没加,等想起来的时候,密码已经提交上去了。
还有一种情况更常见——配置文件被直接放在服务器上,权限设置不当。我记得有一次去一家化工厂做评估,他们的 SCADA 系统配置文件居然对 everyone 可读。我随手打开一看,里面全是 PLC 的通信密码和数据库连接串。
| 配置文件类型 | 常见泄露途径 | 风险等级 |
|---|---|---|
| .properties | 版本控制、服务器权限 | 高 |
| .yaml | 版本控制、日志输出 | 高 |
| .xml | 版本控制、备份文件 | 高 |
| .env | 开发环境泄露、容器镜像 | 极高 |
💡 我的建议:
配置文件里的密钥,至少要做到:
- 使用占位符,比如
${DB_PASSWORD} - 实际值通过外部方式注入,比如环境变量或密钥管理服务
- 配置文件本身设置严格的文件系统权限
3.3 环境变量中的Token:进步了,但还不够
环境变量比前两种方式进步了不少。至少密码不会直接出现在代码和配置文件里了。很多团队觉得:“我把 Token 放在环境变量里,总安全了吧?”
嗯,比硬编码好,但也不是万能的。
环境变量的问题在哪?我总结了几点:
- 进程继承问题:子进程会继承父进程的环境变量。如果你在 shell 里 export 了一个 Token,然后启动了一个子进程,这个子进程也能看到 Token。
- 日志泄露:很多应用会在启动时打印环境变量用于调试。我曾经见过一个日志文件,里面清清楚楚地写着
API_TOKEN=sk-xxxxx。 - 容器镜像:Docker 容器里设置的环境变量,会被打包进镜像层。别人 pull 了你的镜像,就能通过
docker inspect看到。 - 调试工具:
ps aux命令在某些配置下会显示进程的环境变量。
# 不推荐的做法
export API_TOKEN="sk-abcdef123456"
python app.py
# 更好的做法
# 使用密钥管理服务,比如 HashiCorp Vault 或 AWS Secrets Manager
# 应用启动时从密钥服务获取 Token
⚠️ 特别注意:
在 OT 环境中,很多老旧设备不支持环境变量注入。这时候怎么办?我见过有人把 Token 写在启动脚本里,结果脚本又被提交到版本控制里了。嗯,绕了一圈又回来了。
3.4 一张图看懂硬编码凭据的风险路径
下面这张图,是我根据实际项目经验画的。它展示了硬编码凭据从产生到泄露的完整路径。
3.5 为什么工厂环境尤其危险?
你可能觉得,上面说的这些在 IT 系统里也常见啊。没错,但在工厂 OT 环境里,问题更严重。
原因有三:
- 设备生命周期长:工厂里的 PLC、SCADA 系统,一用就是十年八年。代码和配置写死了密码,后面想改?难。很多设备甚至不支持远程修改密码。
- 供应商代码质量参差不齐:我见过太多设备供应商的代码,密码直接硬编码。你跟他说要改,他说“我们一直这么写的”。嗯,很无奈。
- OT 网络隔离的假象:很多人觉得 OT 网络是隔离的,密码泄露了也没事。但现在的工厂,IT/OT 融合是大趋势。一旦攻击者从 IT 侧打进 OT 网络,硬编码的密码就是他们的“万能钥匙”。
📌 总结一下:
硬编码凭据不是“会不会出事”的问题,而是“什么时候出事”的问题。源代码、配置文件、环境变量,这三个地方是重灾区。我的建议很简单:
- 代码里绝对不出现真实密码
- 配置文件使用占位符,实际值外部注入
- 环境变量作为过渡方案,最终迁移到密钥管理服务
别等到出了事再改。那时候,代价就大了。