【学习笔记】Spring Security 01 认识Spring Security的重要特征(Features)

news2024/11/20 19:42:32

Spring Security

零、概述

Spring Security(简称SS)是一个高可用的、可自定义的身份认证和鉴权控制的框架。

类似的框架还有Shiro。

需求场景:

现今流行的web开发中,安全的第一位

原本的鉴权开发流程:springweb自带的过滤器、拦截器等等。涉及到的方面

  • 功能权限
  • 访问权限
  • 菜单权限

使用过滤器需要大量的原生代码——冗余。

所以为了解决这些问题,就需要框架来帮助我们实现。

SS 官网地址以及官方文档

官方地址spring.io/projects/spring-security

官方文档阅读地址:https://docs.spring.io/spring-security/reference/servlet/authentication/index.html#servlet-authentication

image-20231007185421368

学习地址:kuangshenshuo 的B站视频

【【狂神说Java】SpringBoot整合SpringSecurity】https://www.bilibili.com/video/BV1KE411i7bC?vd_source=939c126663135132623f2393e41d7a8a

一、Spring Security快速开始

Spring Security使用的是面向切面编程的思想,也就是说不需要再刻意改动业务逻辑代码,只需要简单的配置,就可以快速接入使用。

1.1 Maven引入SS

直接上pom文件,推荐结合Springboot使用

<dependencies>
	<!-- ... other dependency elements ... -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-security</artifactId>
	</dependency>
</dependencies>

属性参数

<properties>
	<!-- ... -->
	<spring-security.version>6.1.4</spring-security.version>
	<spring.version>6.0.11</spring.version>
</properties>

其他引入方式查看官网:https://docs.spring.io/spring-security/reference/getting-spring-security.html

官方提供的示例:

The completed application can be found in our samples repository. For your convenience, you can download a minimal Reactive Spring Boot + Spring Security application by [clicking here](https://start.spring.io/starter.zip?type=maven-project&language=java&packaging=jar&jvmVersion=1.8&groupId=example&artifactId=hello-security&name=hello-security&description=Hello Security&packageName=example.hello-security&dependencies=webflux,security).

完整的应用程序可以在我们的示例存储库中找到。 为了您的方便,您可以通过单击此处下载最小的反应式 Spring Boot + Spring 安全性应用程序。

1.2 Hello Web Security

二、认识Spring Security的重要特征(Features)

2.1 鉴权认证(Authentication)和 密码存储(Password Strorage)

SS提供了全面的身份验证,可以验证任何尝试访问特定资源的人员身份。一般指当用户输入账户密码后进行验证,验证身份后执行授权。

SS提供了单向转换的密码安全存储功能(无法提供双向密码验证),通常,使用PasswordEncoder存储需要在身份验证时与用户提供的密码比较的密码。

2.1.1 密码存储历史

了解即可。

小结密码的发展史如下:

明文——单向哈希——盐+哈希——自适应函数——长期凭证+短期凭据(比如bcrypt密码加密配合token令牌)

多年来,存储密码的标准机制已经发展。 最初,密码以明文形式存储。 密码被认为是安全的,因为数据存储密码保存在访问它所需的凭据中。 但是,恶意用户能够通过使用SQL注入等攻击找到获取用户名和密码的大型“数据转储”的方法。 随着越来越多的用户凭据公开,安全专家意识到我们需要做更多的事情来保护用户的密码。

然后鼓励开发人员在通过单向哈希(例如SHA-256)运行密码后存储密码。 当用户尝试进行身份验证时,哈希密码将与他们键入的密码的哈希进行比较。 这意味着系统只需要存储密码的单向哈希。 如果发生违规,则仅公开密码的单向哈希。 由于哈希是单向的,并且在计算上很难猜测给定哈希的密码,因此不值得努力找出系统中的每个密码。 为了击败这个新系统,恶意用户决定创建称为彩虹表的查找表( Rainbow Tables)。 他们不是每次都猜测每个密码,而是计算一次密码并将其存储在查找表中。

为了降低彩虹表的有效性,鼓励开发人员使用加盐密码。 将为每个用户的密码生成随机字节(称为盐),而不是仅使用密码作为哈希函数的输入。 盐和用户的密码将通过哈希函数运行以生成唯一的哈希。 盐将以明文形式与用户密码一起存储。 然后,当用户尝试进行身份验证时,哈希密码将与存储的盐的哈希值和他们键入的密码进行比较。 独特的盐意味着彩虹表不再有效,因为每个盐和密码组合的哈希值都不同。

在现代,我们意识到加密哈希(如SHA-256)不再安全。 原因是使用现代硬件,我们可以每秒执行数十亿次哈希计算。 这意味着我们可以轻松地单独破解每个密码

现在鼓励开发人员利用自适应单向函数来存储密码。 使用自适应单向函数验证密码是有意占用大量资源的(它们有意使用大量 CPU、内存或其他资源)。 自适应单向功能允许配置一个“工作因子”,该因子可以随着硬件的改进而增长。 我们建议将“工作因子”调整为大约需要一秒钟来验证系统上的密码。 这种权衡是使攻击者难以破解密码,但又不会太昂贵,以免给您自己的系统带来过多的负担或激怒用户。

Spring Security 试图为“工作因素”提供一个良好的起点,但我们鼓励用户为自己的系统自定义“工作因素”,因为性能因系统而异。 应该使用的自适应单向函数的示例包括 bcrypt, PBKDF2, scrypt 以及 argon2。

由于自适应单向函数有意占用大量资源,因此验证每个请求的用户名和密码可能会显著降低应用程序的性能。 Spring 安全性(或任何其他库)无法加快密码验证的速度,因为安全性是通过使验证资源密集来获得的。 建议用户将长期凭据(即用户名和密码)交换为短期凭据(例如会话和 OAuth 令牌等)。 可以快速验证短期凭据,而不会造成任何安全性损失。

2.1.2 DelegatingPasswordEncoder委派密码编码器

SS提供了自己的解决方案

在 Spring Security 5.0 之前,默认的 PasswordEncoderNoOpPasswordEncoder(需要纯文本密码)。

相当于“密码存储历史”部分的 “BCryptPasswordEncoder”。 但是,这忽略了三个现实世界的问题:

  • 许多应用程序使用无法轻松迁移(easily migrate)的旧密码。
  • 密码存储的最佳做法永远都在更新。
  • 作为一个框架,Spring Security不能经常进行重大更改。

为了解决这些问题,Spring Security 引入了 “DelegatingPasswordEncoder”,它通过以下方式解决了所有问题:

  • 确保使用当前密码存储建议对密码进行编码
  • 允许验证现代和传统格式的密码
  • 允许未来升级编码方式

以下是官方提供的案例https://docs.spring.io/spring-security/reference/features/authentication/password-storage.html,只做了简单的搬运

您可以使用PasswordEncoderFactories方法轻松构建一个DelegatingPasswordEncoder 的实例:

  1. 创建一个默认的委派密码编码器

    PasswordEncoder passwordEncoder =
        PasswordEncoderFactories.createDelegatingPasswordEncoder();
    
  2. 或者,可以创建一个定义的委派密码编码器

    String idForEncode = "bcrypt";
    Map encoders = new HashMap<>();
    encoders.put(idForEncode, new BCryptPasswordEncoder());
    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("argon2", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_2());
    encoders.put("argon2@SpringSecurity_v5_8", Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8());
    encoders.put("sha256", new StandardPasswordEncoder());
    
    PasswordEncoder passwordEncoder =
        new DelegatingPasswordEncoder(idForEncode, encoders);
    

2.1.3 SS的密码存储格式

密码一般的存储格式如下(委派密码编码器的存储格式:

{id}encodedPassword
  • id是用于查找"PasswordEncoder"应使用的标识符

  • encodedPassword是所"PasswordEncoder"的原始编码密码。

  • id必须位于密码的开头,以 开头{,以 结尾}

  • 如果没有找到id,意味着id被设置为空

以下具体举例,所有的原始密码都是“password”:

{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
{noop}password
{pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc
{scrypt}$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=
{sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0

显而易见,**密码前段的大括号{}作为标识符,存储的该密码的加密方式。**决定"PasswordEncoder"使用哪个来编码密码。

Note:一些用户可能担心存储格式是为潜在的黑客提供的。这不是一个问题,因为密码的存储不依赖于算法的秘密。此外,大多数格式在没有前缀的情况下很容易被攻击者识别出来。例如,BCrypt 密码通常以" 2 a 2a 2a"。

2.1.4 密码匹配问题

对应的,密码匹配问题也是根据大括号中的``id来决定使用哪种PasswordEncoder`进行匹配的。

默认情况下,执行方法matches(CharSequence, String)校验密码以及调用未映射的id(包括 null id)的结果为产生异常IllegalArgumentException

可以使用以下方法进行定制化:

DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(PasswordEncoder)

通过使用"id",我们可以匹配任何密码编码,甚至使用最现代的密码编码对密码进行编码。

这很重要,因为与加密不同,密码哈希的设计使得没有简单的方法可以恢复明文。由于无法恢复明文,因此很难迁移密码。为此我们选择了默认包含方便用户迁移的编码方式NoOpPasswordEncoder"(根据上面的案例可以发现,noop是就是明文),以简化入门体验

image-20231007202303764

2.1.5 快速体验SS的委派密码

如果您正在制作演示或样本,那么花时间对用户的密码进行哈希处理会有点麻烦。有一些便利的机制可以使这变得更容易,但这仍然不适合生产。

案例1:默认的密码编码案例(bcrypt)

UserDetails user = User.withDefaultPasswordEncoder()
  .username("user")
  .password("password")
  .roles("user")
  .build();
System.out.println(user.getPassword());
// {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG

如果需要创建多个用户,也是可以复用这个构建器(不需要创建新的实例)

// 只创建一个UserBuilder
UserBuilder users = User.withDefaultPasswordEncoder();
// 构建不同的角色
UserDetails user = users
  .username("user")
  .password("password")
  .roles("USER")
  .build();
UserDetails admin = users
  .username("admin")
  .password("password")
  .roles("USER","ADMIN")
  .build();

尽管这已经对存储的密码进行哈希处理,但密码仍然暴露在内存和编译的源代码中。

因此,对于生产环境来说,它仍然不被认为是安全的。对于生产,您应该在外部对密码进行哈希处理(hash your passwords externally),原文推荐使用SpringBoot CLI。

2.1.6 常用故障排查

2.1.6.1 IllegalArgumentException

当存储的密码之一没有 id时,会发生以下错误

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"

解决方法

解决此问题的最简单方法是弄清楚您的密码当前是如何存储的,并明确提供正确的PasswordEncoder

  • 可以通过公开密码(noop)恢复到之前的加密方式。(个人理解就是跳过ss的用户加密,只套一个{noop}的壳

  • 给所有的密码上加上正确的前缀(已知加密方式的情况下)

    从
    $2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
    改成
    {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
    

详细的映射列表参考: PasswordEncoderFactories

2.1.7 常见的案例

简单总结一下:使用的方法大致是以下几个方法

  • 创建一个对应的编码器
  • 使用编码器的encode(String)方法得到SS的加密结果
  • 使用编码器的matches(原密码,加密后的密码)方法进行密码匹配
2.1.7.1 BCryptPasswordEncoder

广泛支持的 bcrypt 算法对密码进行哈希处理。 为了使其更能抵抗密码破解,bcrypt故意变慢。 与其他自适应单向函数一样,应将其调整为大约需要 1 秒来验证系统上的密码。

推荐:根据系统硬件水平测试调整,设置密码强度使得校验密码需要约1秒。

// Create an encoder with strength 16
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
2.1.7.2 Argon2PasswordEncoder

Argon2是密码哈希竞赛的获胜者。 为了防止自定义硬件上的密码破解,Argon2 是一种故意缓慢的算法,需要大量内存。 与其他自适应单向函数一样,应将其调整为大约需要 1 秒来验证系统上的密码。

// 创建一个全默认的编码器
Argon2PasswordEncoder encoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
2.1.7.3 其他PasswrodEncoder

还有大量其他 “PasswordEncoder” 实现完全是为了向后兼容而存在的。

它们都已弃用,以指示它们不再被视为安全。 但是,没有计划删除它们,因为很难迁移现有的遗留系统。

2.1.7.4 密码存储配置

SS默认使用委派密码编码器。

如果要使用原来的密码编码方式,就使用无操作密码编译器即可:

@Bean
public static NoOpPasswordEncoder passwordEncoder() {
    return NoOpPasswordEncoder.getInstance();
}
// 声明一个"NoOpPasswordEncoder"的bean 名称为"passwordEncoder".

2.1.8 修改密码配置

大多数应用不仅用户提交密码,还必须支持修改密码。

正常我们需要提供一个端口给管理员进行密码管理,你可以通过配置SS来提供该端口,比如原来的应用中修改密码的端口是/change-password,你可以像这样配置SS:

http.passwordManagement(Customizer.withDefaults())

如果不是/change-password,也可以像这样配置

http
    .passwordManagement((management) -> management
        .changePasswordPage("/update-password")
    )

具体用法如下:

要使这段代码生效,您需要在Spring Security的配置文件中进行相应的配置。具体步骤如下:

  1. 打开Spring Security的配置文件(通常是SecurityConfig.javaSecurityConfig.kt)。

  2. 在配置文件中找到适当的位置,添加以下代码片段:

    http
        .passwordManagement(Customizer.withDefaults());
    

    或者,如果您使用XML配置:

    <http>
        <password-management customizer-ref="org.springframework.security.config.Customizer#withDefaults" />
    </http>
    
  3. 如果您的应用程序中的密码更改端点是/change-password,则无需进行其他配置。否则,您可以使用.changePassword().changePasswordUrl("/your-change-password-url")方法来指定自定义的密码更改端点URL。

  4. 保存并关闭配置文件。

这样,当您的应用程序启动时,Spring Security将根据您的配置自动启用密码管理功能,并提供一个标准的密码更改URL供密码管理器使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1088460.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

堆专题3 删除堆顶元素

题目&#xff1a; 样例&#xff1a; 输入 6 3 2 6 5 8 7 输出 7 5 6 3 2 思路&#xff1a; 堆顶的删除&#xff0c;就是取 或者 覆盖掉 h[1]&#xff0c;其中覆盖掉 h[1] 的操作&#xff0c;用向下调整操作堆即可&#xff0c;向下调整的过程相对简单&#xff0c;只需要将堆尾…

如何提高团队协作效率?看完这篇就懂了(附工具)

在竞争激烈的现代工作环境中&#xff0c;团队协作被认为是成功的关键之一。团队协作能够提高效率&#xff0c;增强创造力&#xff0c;并帮助团队成员达成共同目标。无论是在大公司还是小企业中&#xff0c;团队协作都是不可或缺的。在这篇文章中&#xff0c;我们将分享如何通过…

提高测试用例覆盖全面性 5大技巧

测试用例覆盖率越高&#xff0c;有助于尽早发现潜在的问题和Bug&#xff0c;从而保障了软件的质量和稳定性。而测试用例覆盖率可以帮助测试团队评估测试的全面性&#xff0c;发现测试用例的盲点和不足之处&#xff0c;从而提高测试的效率&#xff0c;帮助测试团队优化测试资源的…

OpenCV4(C++)—— 图像连通域的详细分析

文章目录 前言一、connectedComponents函数二、connectedComponentsWithStats函数 前言 图像连通域&#xff0c;其实就是图像分割的一种方法。它通过检测像素之间的连接关系和相似性来划分图像中的区域&#xff0c;以便进行后续处理。图像邻域和图像邻域分析就不介绍了&#x…

Redis第四五六章 持久化事务主从复制

Redis ⽀持 RDB 和 AOF 两种持久化机制&#xff0c;持久化功能有效地避免因进程退出造成数据丢失问题&#xff0c; 当下次重启时利⽤之前持久化的⽂件即可实现数据恢复。 目录 第四章 持久化 4.1 RDB 4.1.1 触发机制 4.1.2 流程说明 4.1.3 RDB ⽂件的处理 4.1.4 RDB 的优…

Autoform R11 R10 R8共存绿色免安装版(解压即用)

使用说明&#xff1a; 如杀毒软件报毒&#xff0c;请关闭。 保证路径正确D:\Autoform 1.首次使用&#xff0c;请点击“首次运行使用.vbs” &#xff08;以后就不用点了&#xff09; 2.打开R8~R11快捷方式即可使用 3.如果提示证书报错&#xff0c; 就重启电脑后就可以了&#…

信必优收到全国性综合类证券客户表扬信

近日&#xff0c;信必优收到全国性综合类证券客户表扬信&#xff0c;客户高度表扬我司驻场员工认真负责的态度和专业扎实的技术能力&#xff0c;任务承担快&#xff0c;工作效率高&#xff0c;对项目顺利开展做出了积极贡献。 客户成立于1988年&#xff0c;在全国21个省级区域…

mars3d使用自己的字体库添加对应的图标

需要引入对应的文件 引入对应的图标文件 使用 效果

【算法-动态规划】两个字符串的删除操作-力扣 583

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

【超分】A Benchmark for Chinese-English Scene Text Image Super-resolution

中英文场景文本图像超分辨率的基准 摘要&#xff1a;场景文本图像超分&#xff08;STISR&#xff0c;Scene Text Image Super-resolution&#xff09;就是将低分辨率图像恢复为具有令人愉快的视觉和可读的文本内容。现有工作都是处理笔画简单的英文字符而不是复杂的中文字符。…

Axure RP医疗在线挂号问诊原型图医院APP原形模板

医疗在线挂号问诊Axure RP原型图医院APP原形模板&#xff0c;是一款原创的医疗类APP&#xff0c;设计尺寸采用iPhone13&#xff08;375*812px&#xff09;&#xff0c;原型图上加入了仿真手机壳&#xff0c;使得预览效果更加逼真。 本套原型图主要功能有医疗常识科普、医院挂号…

【JavaEE初阶】 volatile关键字 与 wait()方法和notify()方法详解

文章目录 &#x1f332;volatile 关键字&#x1f6a9;volatile能保证内存可见性&#x1f6a9;volatile 不保证原子性 &#x1f38b;wait 和 notify&#x1f6a9;wait()方法&#x1f6a9;notify()方法&#x1f6a9;notifyAll()方法&#x1f6a9;理解notify 和 notifyAll &#x…

商贸进销存软件怎么选?

本文将为大家讲解&#xff1a;1、商贸企业进销存流程上的难点&#xff1b;2、商贸企业如何选择进销存系统&#xff1f; 在当今快速发展的商业环境中&#xff0c;有效的进销存&#xff08;Inventory Management&#xff09;管理是商贸企业成功的关键因素之一。然而&#xff0c;…

linux环境下使用lighthouse与selenium

一、安装谷歌浏览器、谷歌浏览器驱动、lighthouse shell脚本 apt update && apt -y upgrade apt install -y curl curl -fsSL https://deb.nodesource.com/setup_18.x | bash apt install -y nodejs apt install -y npm npm install -g lighthouse apt-get install -y …

AutoRunner自动化测试工具

AutoRunner自动化测试工具(简称AR&#xff09;是泽众软件自主研发的自动化测试工具&#xff0c;也是一个自动测试框架&#xff0c;加载不同的测试组件&#xff0c;能够实现面向不同应用的测试。通过录制和编写测试脚本&#xff0c;实现功能测试、回归测试的自动化&#xff0c;自…

UE4中无法保存项目问题

系列文章目录 文章目录 系列文章目录前言一、解决方法 前言 取消&#xff1a;停止保存所有资产并返回编辑器。 重试&#xff1a;尝试再次保存资产。 继续&#xff1a;仅跳过保存该资产。 当我点击继续时&#xff0c;关闭项目&#xff0c;然后重新打开项目&#xff0c;发现之前…

代码随想录

前言 代码随想录算法训练营day04 (不会写数据结构的代码&#xff0c;对着力扣题解和代码随想录网站边敲学) 一、Leetcode24. 两两交换链表中的节点 1.题目 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值…

手部关键点检测1:手部关键点(手部姿势估计)数据集(含下载链接)

手部关键点检测1&#xff1a;手部关键点(手部姿势估计)数据集(含下载链接) 目录 手部关键点检测1&#xff1a;手部关键点(手部姿势估计)数据集(含下载链接) 1. 前言 2. 手部检测数据集&#xff1a; &#xff08;1&#xff09;Hand-voc1 &#xff08;2&#xff09;Hand-vo…

FMI标准:实现SkyEye与Simulink无需缝合的联合仿真

在汽车工业、航空、机电装备等领域存在着不同的应用、建模系统。在解决不同问题的过程中&#xff0c;为了仿真完整的系统&#xff0c;往往需要在不同的仿真程序之间进行交互&#xff0c;并且为了实现完整的调试&#xff0c;系统的集成必须确保来自不同供应商的仿真环境能够协同…

腾讯云 CODING 界面全新升级,代码仓库 Rebase 变基合并、批量复制事项等功能上线!

点击链接了解详情 金秋十月&#xff0c;腾讯云 CODING DevOps 焕新上线&#xff01;本次更新&#xff0c;我们不仅推出了全新的用户界面&#xff0c;还推出了一系列重磅产品能力&#xff0c;满足广大用户的日常研发与协作所需。 以下是 CODING 新功能速递&#xff0c;快来看看是…