前言
这是我做的第一个项目。前几天我对安全的理解只停留在“别写出 bug 就行”。直到在测试数据库时,亲眼看到 user_password 字段里躺着一串串明文密码,才想起之前刷到的视频里一句话:“明文密码 = 红线”。本文记录我从明文存储到使用 BCrypt 的全过程,留给也在苦苦写项目的同学做参考。
问题爆发:数据库里的“裸奔”密码
项目初期我只想先跑通流程,直接把前端传来的密码丢进数据库。控制层代码大概是这样:
1 2 3 4 5 6 7 8 9
| @PostMapping("/register") public Result register(@RequestBody User user) { if (user.getPassword().length() < 8) { return Result.error("密码长度不足"); } userMapper.insert(user); return Result.success(); }
|
当我用 Navicat 打开数据表,"12345678"、"abcdefg" 等弱密码全在里面。此刻我才意识到:如果数据库被拖库,所有用户账号都会暴露。
解决过程:BCrypt 的救赎
1. 选型
查资料后锁定几个常见方案:
MD5:不可逆,但彩虹表和 GPU 暴力破解太快;
SHA:同样属于快速哈希,对密码保护不够;
BCrypt:自带盐值,计算慢,可拖慢暴力破解。
结合 Spring 生态,我直接使用 BCryptPasswordEncoder,不必自己维护盐值,整合也很顺。
2. 代码改造
引入依赖
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
|
注册加密 Bean
1 2 3 4 5 6 7
| @Configuration public class SecurityConfig { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
|
改造注册 / 登录逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Service public class UserServiceImpl implements UserService {
@Autowired private PasswordEncoder passwordEncoder;
@Override public void register(User user) { String encodedPassword = passwordEncoder.encode(user.getPassword()); user.setPassword(encodedPassword); userMapper.insert(user); }
@Override public User login(String account, String password) { User user = userMapper.selectByAccount(account); if (user == null) { throw new BusinessException("用户不存在"); } if (!passwordEncoder.matches(password, user.getPassword())) { throw new BusinessException("密码错误"); } return user; } }
|
3. 新坑:字段长度不够
BCrypt 生成的哈希大约 60 个字符,而我的 user_password 是 varchar(50)。插入时报错,只能赶紧迁表:
1 2
| ALTER TABLE user MODIFY COLUMN user_password VARCHAR(60) NOT NULL COMMENT '密码哈希';
|
总结
这次踩坑的收获:
- 明文密码绝对不能入库,BCrypt 是上手友好的方案;
- 哈希字符串会更长,库表字段要预留空间;
- 善用框架提供的工具,别重复造轮子。
下一篇我应该还会记录在这个项目遇到的其他问题,希望还能坚持写下去,欢迎催更!
更新 – 相关文章
这个用户中心项目系列的其他文章: