SpringSecurity(学习笔记) --密码强度调整及加密的多种算法以及密码升级!

重点标识

密码加密的重要性这里就不说了,现在应该也没有明文存储的密码了。

这篇,我们主要了解一下Security的加密方式,所运用的思路。

Security采用单向自适应函数来进行加密,有意增加字符串比较时间,增加破解系统的难度,只能从明文变成密文,不能从密文变成明文。

我们也可以手动调整它的参数,官方一般推荐登录认证在一秒左右,性能较强的系统,可以调高一点,性能较差,可以调低一点。

原理解析

我们简单了解一下Security的加密认证方式,实际上主要就是PasswordEncoder这个接口,提供了三个方法:

encode 加密
matches 比较密码
upgradEncoding 升级密码(密码的自动升级)

public interface PasswordEncoder {
    String encode(CharSequence rawPassword);

    boolean matches(CharSequence rawPassword, String encodedPassword);

    default boolean upgradeEncoding(String encodedPassword) {
        return false;
    }
}

PasswordEncoder有许多干活的,Security默认使用的就是BCryptPasswordEncoder这种加密算法。
在这里插入图片描述

调整密码强度

密码强度,针对于一些性能较强的系统来说,及时的响应对于用户体验来说是一种优势,但从破解层面来看,其实也是一种劣势。

Security强度的范围为小于4,大于31,其余都是不对的。

 BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        for (int i = 0; i < 10; i++) {
            System.out.println(bCryptPasswordEncoder.encode("123"));
        }

在这里插入图片描述
这张图的意思$2a$10,就是强度为10;看一下源码对它的定义,Security默认-的密码强度是-1 ,源码中给的就是10;,验证一下。
在这里插入图片描述

多种加密共存

Security提供DelegatingPasswordEncoder,对多种加密方式统一进行管理。
在PasswordEncoderFactories存了一堆,看看

public static PasswordEncoder createDelegatingPasswordEncoder() {
        String encodingId = "bcrypt";
        Map<String, PasswordEncoder> encoders = new HashMap();
        encoders.put(encodingId, new BCryptPasswordEncoder());
        encoders.put("ldap", new LdapShaPasswordEncoder());
        encoders.put("MD4", new Md4PasswordEncoder());
        encoders.put("MD5", new MessageDigestPasswordEncoder("MD5"));
        encoders.put("noop", NoOpPasswordEncoder.getInstance());
        encoders.put("pbkdf2", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5());
        encoders.put("pbkdf2@SpringSecurity_v5_8", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8());
        encoders.put("scrypt", SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1());
        encoders.put("scrypt@SpringSecurity_v5_8", SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8());
        encoders.put("SHA-1", new MessageDigestPasswordEncoder("SHA-1"));
        encoders.put("SHA-256", new MessageDigestPasswordEncoder("SHA-256"));
        encoders.put("sha256", new StandardPasswordEncoder());
        encoders.put("argon2", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2());
        encoders.put("argon2@SpringSecurity_v5_8", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8());
        return new DelegatingPasswordEncoder(encodingId, encoders);
    }
  • {bcrypt}$2a 10 10 10mwLuXtPsOczW2H4Iy2W7uOyl/kXQJpf0NR6CplPG4ZlzUniTB9Ei.
    看一下它生成密文的内容,从左到依次是加密方法,强度,以及加密后的密文。

这个是他的加密源码拼接方法。


    public String encode(CharSequence rawPassword) {
        String var10000 = this.idPrefix;
        return var10000 + this.idForEncode + this.idSuffix + this.passwordEncoderForEncode.encode(rawPassword);
    }

可以简单的测一些,这是他默认的

  String encodingId = "bcrypt";
        Map<String, PasswordEncoder> encoders = new HashMap();
        encoders.put(encodingId, new BCryptPasswordEncoder());
        encoders.put("ldap", new LdapShaPasswordEncoder());
        encoders.put("MD4", new Md4PasswordEncoder());
        encoders.put("MD5", new MessageDigestPasswordEncoder("MD5"));
        encoders.put("noop", NoOpPasswordEncoder.getInstance());
        encoders.put("pbkdf2", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5());
        encoders.put("pbkdf2@SpringSecurity_v5_8", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8());
        encoders.put("scrypt", SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1());
        encoders.put("scrypt@SpringSecurity_v5_8", SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8());
        encoders.put("SHA-1", new MessageDigestPasswordEncoder("SHA-1"));
        encoders.put("SHA-256", new MessageDigestPasswordEncoder("SHA-256"));
        encoders.put("sha256", new StandardPasswordEncoder());
        encoders.put("argon2", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2());
        encoders.put("argon2@SpringSecurity_v5_8", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8());
        DelegatingPasswordEncoder encodingId1 = new DelegatingPasswordEncoder(encodingId, encoders);
        for (int i = 0; i < 10; i++) {
            System.out.println(encodingId1.encode("123"));
        }

换个SHA-256试一试

  DelegatingPasswordEncoder encodingId1 = new DelegatingPasswordEncoder("SHA-256", encoders);
        for (int i = 0; i < 10; i++) {
            System.out.println(encodingId1.encode("123"));
        }

试一下密码比对

 boolean matches = encodingId1.matches("123", "{SHA-256}{xZpsNg4SRrJeGZcjAM9i0jbGW7WbECXbxOIL/Um5mPo=}06c3ea9b29dea28920d8698fbc8321d9b8995718e809b6513416a7e5643d45ec");
        System.out.println(matches);

自然就是true,没问题的。

密码升级

我们知道,md5被破解,已经不安全了,如果碰到一些老旧的系统,需要升级,更改加密方式,虽然说Md5已经被破解,但是数据库存储的肯定也是密文,无法知道明文,一个个破解,不规范,也不符合现实。

这种情况下,我们就可以考虑Security的密码升级。

方案如下:

用户登录的时候,判断用户密码是否需要升级,如果需要升级,则会触发这个方法,进行升级。

但是这个,只能使用DelegatingPasswordEncoder,否则系统中只存在一种加密方式,无法进行升级。

可以在config中配置,不配置就是默认的密码加密策略,如下。

 @Bean
    PasswordEncoder passwordEncoder(){
        String encodingId = "bcrypt";
        Map<String, PasswordEncoder> encoders = new HashMap();
        encoders.put(encodingId, new BCryptPasswordEncoder());
        encoders.put("ldap", new LdapShaPasswordEncoder());
        encoders.put("MD4", new Md4PasswordEncoder());
        encoders.put("MD5", new MessageDigestPasswordEncoder("MD5"));
        encoders.put("noop", NoOpPasswordEncoder.getInstance());
        encoders.put("pbkdf2", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5());
        encoders.put("pbkdf2@SpringSecurity_v5_8", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8());
        encoders.put("scrypt", SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1());
        encoders.put("scrypt@SpringSecurity_v5_8", SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8());
        encoders.put("SHA-1", new MessageDigestPasswordEncoder("SHA-1"));
        encoders.put("SHA-256", new MessageDigestPasswordEncoder("SHA-256"));
        encoders.put("sha256", new StandardPasswordEncoder());
        encoders.put("argon2", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2());
        encoders.put("argon2@SpringSecurity_v5_8", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8());
        DelegatingPasswordEncoder delegatingPasswordEncoder = new DelegatingPasswordEncoder(encodingId, encoders);
       return delegatingPasswordEncoder;
    }

密码加密升级的策略,看他是不是默认的加密方案,是,再看密码强度是不是一样,一样则不变,不是,则改为默认的加密方案,或者强度不一致,也会进行升级。

升级的方式很简单,我们之前在整合Mybatis的时候,有一个UserService,在里面实现一个接口就行了UserDetailsPasswordService #updatePassword。


@Service
public class UserService implements UserDetailsService, UserDetailsPasswordService {


    @Autowired
    UserMapper userMapper;

    /**
     * 当用户登录的时候,会自动触发到这里,去数据库查询
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        User u = userMapper.loadUserByUsername(username);
        if(u == null){
            throw new UsernameNotFoundException("用户名不存在!");
        }
        return u;
    }

    @Override
    public UserDetails updatePassword(UserDetails user, String newPassword) {

        //根据用户名更新

        userMapper.updatePassword(user.getUsername(),newPassword);
        return user;
    }
}
 <update id="updatePassword">
        UPDATE USER SET PASSWORD=#{newPassword}
          WHERE USERNAME=#{username}

      </update>

这样,就OK了。

结语

又掌握一招,积水成渊,蛟龙生焉!

  • 23
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 前后端分离是一种将前端界面与后端逻辑进行分离开发的架构方式,使得前端与后端可以并行开发。OAuth 2.0是一种授权框架,用于授权和认证流程的规范化,而Spring Security是一个在Java中实现安全控制的框架,提供了大量的安全特性。Spring Authorization Server是Spring Security中用于实现授权服务器的模块,它支持OAuth 2.0的各种授权模式。 密码模式是OAuth 2.0中的一种授权模式,它允许用户通过提交用户名和密码来获取访问令牌,然后使用该令牌来访问受保护的资源。在前后端分离的架构中,可以使用Spring Security配合Spring Authorization Server来实现密码模式的认证和授权。 在密码模式下,前端首先需要收集用户的用户名和密码,并将其发送给后端。后端使用Spring Security提供的密码编码器对密码进行加密,并验证用户名和密码的正确性。如果验证通过,则后端向客户端颁发一个访问令牌,通常是一个JWT(JSON Web Token)。前端使用获得的访问令牌来访问需要受保护的资源,每次请求将该令牌作为Authorization头的Bearer字段发送给后端进行验证。后端可以使用Spring Security的资源服务器来验证该令牌的有效性,并根据用户的权限控制对资源的访问。 使用Spring Security和Spring Authorization Server的密码模式可以实现安全的前后端分离架构。通过合理配置和使用安全特性,可以保障用户的身份认证和资源的授权,确保系统的安全性。 ### 回答2: 前后端分离是一种软件架构模式,前端和后端通过使用API进行通信,分别负责处理用户界面和数据逻辑。OAuth 2.0是一种用于授权的开放标准协议,它允许用户在第三方应用程序中授权访问其受保护的资源。Spring Security是Spring框架中的一个模块,提供了身份验证和授权功能。 在前后端分离的架构中,前端应用程序通常需要使用OAuth 2.0协议进行用户授权,以访问后端应用程序的受保护资源。为了实现密码模式,我们可以使用Spring Security的模块之一,即spring-authorization-server。 spring-authorization-server是Spring Security的一个子模块,用于实现OAuth 2.0协议中的授权服务器。密码模式是OAuth 2.0协议中的一种授权模式,允许前端应用程序通过用户的用户名和密码进行授权。密码模式在安全性上有一定的风险,因此在实际应用中需要谨慎使用。 使用spring-authorization-server的密码模式,我们可以在前端应用程序中收集用户的用户名和密码,并将其提交给后端应用程序进行验证。后端应用程序将使用Spring Security进行身份验证,并向前端应用程序颁发一个访问令牌,该令牌可以用于后续的API请求。 通过使用前后端分离、OAuth 2.0和spring-authorization-server的密码模式,我们可以实现安全的用户授权和身份验证机制,确保只有经过授权的用户才能访问受保护的资源。这种架构模式能够提高系统的安全性和可扩展性,适用于各种类型的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值