Spring security 3.1.4 和 ShaPasswordEncoder 弃用

Posted

技术标签:

【中文标题】Spring security 3.1.4 和 ShaPasswordEncoder 弃用【英文标题】:Spring security 3.1.4 and ShaPasswordEncoder deprecation 【发布时间】:2013-06-18 21:50:02 【问题描述】:

今天我将我正在开发的应用程序的 Spring Security 版本从 3.1.3 升级到了 3.1.4,我注意到 org.springframework.security.authentication.encoding.ShaPasswordEncoder 类上有一个弃用警告。

所以我切换到新的org.springframework.security.crypto.password.StandardPasswordEncoder 实现。

我让它工作了,我可以注册一个新用户并在我的应用程序中登录,但我担心的是,我无法使用以前的 ShaPasswordEncoder 和我的自定义 salt 生成的密码登录。

由于我有一个已经注册了许多用户的数据库,我应该怎么做才能在不使旧编码密码失效的情况下切换实现? 有没有可能?

另请参阅:How to use new PasswordEncoder from Spring Security

【问题讨论】:

【参考方案1】:

如果您想切换到更安全的密码编码机制,那么我建议您使用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 哈希值执行多次更新将是微不足道的。

【讨论】:

感谢您的代码。这或多或少是 Spiff 建议的。相反,我的目标是能够升级到 Spring Security 的未来版本,而无需同时拥有两个实现,而且这个解决方案只有在每个用户都登录的情况下才有效。我希望它会引入一个与旧版本兼容的实现ShaPasswordEncoder. 如果用户从未登录,那么可能值得决定这些帐户是否值得维护(在适当的审查期之后)。如果它们处于非活动状态,您可以暂时禁用它们并向用户发送邮件,要求他们重置密码。不鼓励使用旧密码编码器,因为它们相对不安全、容易出错并且与其他系统不兼容。这些类已被弃用以阻止它们在新应用中的使用,但如果您真的不想使用更安全的选项,没有什么可以阻止您使用它们。【参考方案2】:

我尝试在已接受的答案中添加评论,但可惜我还没有足够的信誉。 :(

我认为接受答案的代码 sn-p 在更新数据库中的密码时具有潜在危险。如果 ShaPasswordEncoder 在加密时产生相同的结果(这就是假设可以找到旧密码的原因,并且我验证了这绝对是正确的,至少在 ShaPasswordEncoder 上使用 null salt),您仍然不能保证密码在所有用户中是唯一的。您可能会碰巧与系统上的另一个用户共享相同的密码,并且该 SQL 代码最终会更改所有碰巧拥有您密码的用户。

我认为最安全的策略是不更新用户密码,而是提供一种迁移策略,计划最终删除 ShaPasswordEncoder。

使用提供的示例代码。 删除更新数据库的代码。 添加诸如“忘记密码”或“生成新密码”之类的功能,以处理删除 ShaPasswordEncoder 后用户未创建新密码的最终情况。就像您升级到已将其删除的 Spring Security 时一样,或者选择自己将其删除。 更新您的文档或明确说明,在软件的下一个主要版本中,用户将不得不重新保存他们的密码或必须使用前面提到的密码重置功能。 给用户一个主要版本发布周期的宽限期以进行转换(他们可能不会这样做,只是被重置密码所困)。

【讨论】:

这是一个很好的观点。但是,我认为与现有情况相比,这并不危险,也不应该推迟更新。解决方法也很简单。我更新了我的答案以添加一些额外的想法。【参考方案3】:

这是一个很好的问题,我期待着阅读一些答案。

AFAIK 不可能在一次大规模更新中完成:您无法从哈希中检索原始字符串。您必须在登录尝试期间检查提交的密码是否与任一策略匹配,并在必要时将其转换为新策略,但这意味着您必须同时使用这两种编码策略,直到所有用户都已登录,因此所有密码都已转换。对于新加入的开发人员来说不是很方便,也不一定直观。

【讨论】:

以上是关于Spring security 3.1.4 和 ShaPasswordEncoder 弃用的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security 3.1.4:由于anonymousUser身份验证无法访问目标页面

Spring Security 3.1.4 taglib 授权/身份验证不适用于 Tomcat 7 上 JSF 2.2 中的角色层次结构

在 Spring security OAUTH 中定义多个 TokenStore(s)

Spring Security:3. What’s New in Spring Security 4.2 (新功能)

无法为会话序列化会话属性 SPRING_SECURITY_CONTEXT

如何使用 XML 使用 Spring Security Oauth2 启用 /oauth/check_token