【缺陷周话】第25期:硬编码密码
字数 1450 2025-08-18 11:38:08
硬编码密码安全缺陷详解与防范指南
1. 硬编码密码概述
硬编码密码是指在程序源代码中直接写入密码或敏感凭证的处理方式。这是一种常见但危险的安全实践,会导致严重的安全隐患。
1.1 基本定义
- CWE ID: 259 (Use of Hard-coded Password)
- 危害等级: 中高风险
- 影响范围: 所有包含认证机制的软件系统
1.2 主要问题
- 维护困难:密码变更需要修改源代码并重新部署
- 安全风险:源代码或字节码泄露会导致密码暴露
- 权限扩散:所有能访问代码的人员都能获取敏感凭证
2. 硬编码密码的危害
2.1 实际影响
- 远程攻击者可获取管理控制权限
- 本地用户可读取配置文件执行任意代码
- 数据库等敏感系统可能被未授权访问
2.2 真实漏洞案例
| CVE编号 | 受影响系统 | 危害描述 |
|---|---|---|
| CVE-2019-6499 | Teradata Viewpoint | 视点数据库帐户使用硬编码密码 |
| CVE-2018-18006 | Ricoh myPrint | 可访问外部公开的WSDL API |
| CVE-2018-6387 | iBall iB-WRA150N | 管理员和普通账户都有硬编码密码 |
| CVE-2018-5726 | MASTER IPCAMERA01 | 通过HTTP请求获取用户名密码 |
3. 代码示例与分析
3.1 缺陷代码示例(Java)
// 连接数据库执行SQL语句
public void bad() throws Throwable {
String data;
data = "root"; // 硬编码用户名
String password = "123456"; // 硬编码密码(缺陷点)
Connection connection = null;
Properties connectionProps = new Properties();
connectionProps.put("user", data);
connectionProps.put("password", password);
connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test",
connectionProps);
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM users");
// 处理结果...
}
问题分析:
- 第4行直接硬编码了数据库密码"123456"
- 密码会随代码一起编译到字节码中
- 反编译工具可轻易获取此密码
3.2 检测方法
使用静态代码分析工具(如360代码卫士)可检测此类问题:
- 识别字符串常量中的密码模式
- 跟踪密码变量的使用路径
- 标记直接用于认证的硬编码凭证
4. 修复方案
4.1 修复代码示例
// 使用加密配置文件存储凭证
public void good() throws Throwable {
String data;
// 从加密配置文件中获取凭证
Properties prop = getProperties();
data = prop.getProperty("username");
String password = prop.getProperty("password");
Connection connection = null;
Properties connectionProps = new Properties();
connectionProps.put("user", data);
connectionProps.put("password", password);
connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test",
connectionProps);
// ...其余代码
}
// 封装获取加密配置的方法
private Properties getProperties() throws Throwable {
String decryptedUsername;
String decryptedPassword;
Properties prop = new Properties();
// 读取配置文件
FileInputStream stream = new FileInputStream("db.properties");
prop.load(stream);
// 获取并解密凭证
decryptedUsername = decrypt(prop.getProperty("username_encrypted"));
decryptedPassword = decrypt(prop.getProperty("password_encrypted"));
Properties credentials = new Properties();
credentials.put("username", decryptedUsername);
credentials.put("password", decryptedPassword);
return credentials;
}
// 解密方法(示例)
private String decrypt(String input) {
// 实现解密逻辑
return input; // 实际应返回解密后的字符串
}
4.2 修复要点
-
外部化配置:
- 将凭证移至外部配置文件(如db.properties)
- 配置文件不纳入版本控制系统
-
加密存储:
- 配置文件中的密码应加密存储
- 使用强加密算法(如AES)
-
安全访问:
- 配置文件设置适当权限(如600)
- 运行时动态解密使用
-
维护优势:
- 密码变更只需修改配置文件
- 无需重新编译部署代码
5. 最佳实践建议
5.1 凭证管理原则
- 绝不硬编码:任何形式的凭证都不应出现在源代码中
- 最小权限:使用具有最小必要权限的账户
- 定期轮换:建立密码定期更换机制
5.2 推荐方案
-
配置服务器:
- 使用Spring Cloud Config等配置中心
- 动态获取运行时配置
-
密钥管理服务:
- AWS KMS、HashiCorp Vault等专业服务
- 提供加密、解密和轮换功能
-
环境变量:
- 适用于容器化部署
- 结合Docker secrets等机制
-
认证代理:
- 使用IAM角色等临时凭证机制
- 避免长期有效的静态凭证
5.3 防御深度策略
-
代码审查:
- 建立硬编码密码检查清单
- 使用SAST工具自动化扫描
-
运行时保护:
- 监控异常认证尝试
- 设置凭证使用告警
-
应急响应:
- 预设凭证泄露处理流程
- 准备快速凭证吊销机制
6. 总结
硬编码密码是常见但高危的安全缺陷,通过本指南介绍的方法,开发团队可以:
- 识别现有代码中的硬编码密码问题
- 采用安全的凭证管理实践进行修复
- 建立预防机制避免未来引入类似缺陷
遵循"不信任、不存储明文、最小权限"的原则,可有效降低因凭证管理不当导致的安全风险。