今天我将我正在处理的应用程序的spring安全版本从3.1.3升级到3.1.4,我注意到org.springframework.security.authentication.encoding.ShaPasswordEncoder
类的弃用警告。
所以我切换到了新的org.springframework.security.crypto.password.StandardPasswordEncoder
实现。
我有它工作,我能够注册一个新用户并登录我的应用程序,但是,正如我所担心的,我无法使用以前的ShaPasswordEncoder和我的自定义盐生成的密码登录。
由于我有一个已经注册了许多用户的数据库,我该怎么做才能切换实现而不会使旧的编码密码失效? 它甚至可能吗?
答案 0 :(得分:18)
如果您想切换到更安全的密码编码机制,我建议您使用BCrypt。我会使用类似的东西来迁移您的用户:
// Implement the old PasswordEncoder interface
public class MigrateUsersPasswordEncoder implements PasswordEncoder {
@Autowired
ShaPasswordEncoder legacyEncoder;
@Autowired
JdbcTemplate template;
BCryptPasswordEncoder bcryptEncoder = new BCryptPasswordEncoder();
@Override
public String encodePassword(String rawPass, Object salt) {
return bcryptEncoder.encode(rawPass);
}
@Override
public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
if (legacyEncoder.isPasswordValid(encPass, rawPass, salt)) {
template.update("update users set password = ? where password = ?", bcryptEncoder.encode(rawPass), encPass);
return true;
}
return bcryptEncoder.matches(rawPass, encPass);
}
}
您可以按密码字段的格式检查已迁移的用户比例。 BCrypt字符串具有以$
符号开头的独特语法。
其他一个答案指出此代码可能会意外地同时更新多个密码。问题表明正在使用定制盐,因此如果随机选择盐,碰撞的可能性可以忽略不计,但情况可能并非总是如此。如果更新了两个密码,问题是什么?然后可以从bcrypt哈希中检测到帐户具有相同的密码。无论如何都是这种情况,因为它要求SHA哈希值与更新相同。如果您认为这可能是一个问题(例如,由于选择差的盐或甚至使用未加盐的哈希),那么修改SQL以检测它并使用单独的BCrypt哈希值执行多个更新将是微不足道的。
答案 1 :(得分:3)
我试图在接受的答案中添加评论,但唉,我还没有足够的信誉。 :(
我相信接受答案的代码段在更新数据库中的密码时可能会有危险。如果ShaPasswordEncoder在加密时产生相同的结果(这就是为什么假设可以找到旧密码的原因,并且我确认这至少在ShaPasswordEncoder上使用空盐是肯定的),你仍然无法保证密码在所有用户中都是唯一的。您可以偶然地与系统上的另一个用户共享相同的密码,并且该SQL代码最终会更改碰巧拥有您密码的所有用户。
我认为最安全的策略是不更新用户的密码,而是提供一个迁移策略,计划最终删除ShaPasswordEncoder。
答案 2 :(得分:1)
这是一个很好的问题,我期待着阅读一些答案。
AFAIK在单个批量更新中无法做到:您无法从哈希中检索原始字符串。您必须在登录尝试期间检查提交的密码是否与策略匹配,并在必要时将其转换为新策略,但这意味着您必须使用两种编码策略,直到所有用户都已登录,因此所有密码都已转换。对于新开发人员来说,不太方便,也不一定直观。