Spring-Security

Spring Security 6.3 中的新特性

1、简介 Spring Security 6.3 版在框架中引入了一系列安全增强功能。本文将带你了解其中一些最值得注意的特性,重点介绍它们的优点和用法。 2、被动式的 JDK 序列化支持 Spring Security 6.3 包含被动式的 JDK 序列化支持(Passive JDK Serialization Support),首先先来了解一下相关的问题和困扰。 2.1、Spring Security 的序列化设计 在 6.3 版本之前,Spring Security 对其类在不同版本之间通过 JDK Serialization 进行序列化和反序列化有严格的策略。这个限制是框架的一个有意设计决策,旨在确保安全性和稳定性。其理由是防止使用不同版本的Spring Security 反序列化在一个版本中序列化的对象时出现不兼容性和安全漏洞。 这一设计的一个关键方面是在整个 Spring Security 项目中使用全局 serialVersionUID。在 Java 中,序列化和反序列化过程使用唯一标识符 serialVersionUID 来验证加载的类是否与序列化对象完全一致。 通过为 Spring Security 的每个发布版本维护一个唯一的全局 serialVersionUID,该框架可确保一个版本的序列化对象无法使用另一个版本进行反序列化。这种方法有效地创建了一个版本屏障,防止了序列化版本 serialVersionUID 值不匹配的对象被反序列化。 例如,Spring Security 中的 SecurityContextImpl 类表示 Security Context 信息。该类的序列化版本包含该版本特有的 serialVersionUID。当尝试在不同版本的 Spring Security 中反序列化该对象时,serialVersionUID 不匹配会阻止该过程成功进行。 2.2、序列化设计带来的困扰 在优先增强安全性的同时,这种设计策略也带来了一些困扰。开发人员通常将 Spring Security 与 Spring Session 等其他 Spring 库集成,以管理用户登录会话(Session)。这些会话包含重要的用户身份认证和 Security Context 信息,通常通过 Spring Security 类实现。此外,为了优化用户体验并提高应用的可扩展性,开发人员通常会在各种持久存储解决方案(包括数据库)中存储这些会话数据。

Spring Security 检测密码是否泄露

1、概览 在构建处理敏感数据的 Web 应用时,确保用户密码的安全性非常重要。密码安全的一个重要方面是检查密码是否泄露,这通常是由于密码出现在 数据泄露事件 中。 Spring Security 6.3 引入了一项新功能,让我们可以轻松检查密码是否被已泄露。 本文将带你了解 Spring Security 中新的 CompromisedPasswordChecker API 以及如何将其集成到 Spring Boot 应用中。 2、密码泄露 密码泄露是指在数据泄露事件中暴露的密码,使其容易受到未经授权的访问。攻击者通常在凭证填充和密码填充攻击中使用这些泄露的密码,在多个网站上使用泄露的用户名-密码对,或在多个账户上使用通用密码。 要降低这种风险,关键是要在创建账户前检查用户密码是否泄露。 同样重要的是要注意,以前有效的密码可能会随着时间的推移而泄露,因此建议不仅在创建账户时,而且在登录过程中或任何允许用户更改密码的过程中都要检查密码是否泄露。如果登录尝试因检测到密码泄露而失败,可以提示用户重设密码。 3、CompromisedPasswordChecker Spring Security 提供了一个简单的 CompromisedPasswordChecker 接口,用于检查密码是否被泄露: public interface CompromisedPasswordChecker { CompromisedPasswordDecision check(String password); } 该接口只暴露了一个 check() 方法,该方法将密码作为输入,并返回一个 CompromisedPasswordDecision 的实例,表明密码是否已被破解/泄露。 check() 方法需要明文密码,因此必须在使用 PasswordEncoder 加密密码之前调用该方法。 3.1、配置 CompromisedPasswordChecker Bean 要在应用中启用密码泄露检查,需要声明 CompromisedPasswordChecker 类型的 Bean: @Bean public CompromisedPasswordChecker compromisedPasswordChecker() { return new HaveIBeenPwnedRestApiPasswordChecker(); } HaveIBeenPwnedRestApiPasswordChecker 是 Spring Security 提供的 CompromisedPasswordChecker 的默认实现。

Spring Security 6.3.0 发布

Spring Security 6.3.0 正式发布! 6.3 版本带来了几个引人注目的特性,如下: 长期的 JDK 序列化向后兼容性 新的方法安全注解和功能 密码受损检查 支持 OAuth 2.0 令牌交换 该版本将包含在即将发布的 Spring Boot 3.3 GA 版本中。 ⭐ 新特性 为 OAuth2AuthorizedClientId 添加 Getter #13648 为 JwtDecoders 添加超时默认值 #14890 文档:添加了将 GrantedAuthorityDefaults 声明为基础架构 Bean 的提示 #15065 改进全局身份认证(Global Authentication)的日志记录 #14711 文档小修正 #15043 需要对使用 Kotlin DSL 的导入进行微小的文档更新 #14969 OAuth2 客户端身份认证文档不完整 #14982 校对 CasAuthenticationFilter 文档 #14883 将 “Spring Boot 2.x” 替换为 “Spring Boot” #14919 简化禁用 “application/x-www-form-urlencoded” 编码 Client ID 和 Secret#14859 支持为依赖方注册元素指定标识符 #14487 更新 6.

Spring Boot 中 Spring Security 自动配置

1、概览 本文将带你了解 Spring Boot 中 Spring Security 的自动配置、默认安全配置,以及如何在需要时禁用或自定义它。 2、默认的 Spring Security 设置 首先添加 security starter 依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> 这包含初始/默认 Security 配置的 SecurityAutoConfiguration 类。 这里没有指定版本,因为项目使用了 spring-boot-starter-parent 作为 parent。 默认情况下,应用会启用身份验证,内容协商(Content Negotiation)用于确定应使用 basic 还是 formLogin。 有一些预定义的配置属性: spring.security.user.name= spring.security.user.password= 如果不使用预定义属性 spring.security.user.password 配置密码并启动应用,默认密码将随机生成并打印在控制台日志中: Using default security password: c8be15da-4489-4491-9dc6-fab3f91435c7 有关更多默认值,请参阅 Spring Boot 中文文档中的 属性配置。 3、禁用自动配置 要禁止 Security 自动配置并添加我们的自定义配置,需要排除 SecurityAutoConfiguration 自动配置类。 可以通过 @SpringBootApplication 注解中的 exclude 属性来实现: @SpringBootApplication(exclude = { SecurityAutoConfiguration.class }) public class SpringBootSecurityApplication { public static void main(String[] args) { SpringApplication.

新版 Spring Security 中的路径匹配机制

Spring Security 是一个功能强大且可高度定制的安全框架,它提供了一套完整的解决方案,用于保护基于 Spring 的应用。在 Spring Security 中,路径匹配是权限控制的核心部分,它决定了哪些请求可以访问特定的资源。本文将带你详细了解 Spring Security 中的路径匹配策略,并提供相应的代码示例。 在旧版的 Spring Security 中,路径匹配方法有很多,但是新版 Spring Security 对这些方法进行了统一的封装,都是调用 requestMatchers 方法进行处理: public C requestMatchers(RequestMatcher... requestMatchers) { Assert.state(!this.anyRequestConfigured, "Can't configure requestMatchers after anyRequest"); return chainRequestMatchers(Arrays.asList(requestMatchers)); } requestMatchers 方法接收一个 RequestMatcher 类型的参数,RequestMatcher 是一个接口,这个接口是一个用来确定 HTTP 请求是否与给定的模式匹配的工具。这个接口提供了一种灵活的方式来定义请求的匹配规则,从而可以对不同的请求执行不同的安全策略。 所以在新版 Spring Security 中,不同的路径匹配分方案实际上就是不同的 RequestMatcher 的实现类。 1. AntPathRequestMatcher AntPathRequestMatcher 是 Spring 中最常用的请求匹配器之一,它使用 Ant 风格的路径模式来匹配请求的 URI。 1.1 什么是 Ant 风格的路径模式 Ant 风格的路径模式(Ant Path Matching)是一种用于资源定位的模式匹配规则,它源自 Apache Ant 这个 Java 构建工具。在 Ant 中,这种模式被用来指定文件系统中的文件和目录。由于其简单性和灵活性,Ant 风格的路径模式也被其他许多框架和应用程序所采用,包括 Spring Security。

使用 Key 和 SecretKey 签发 JWT Token

1、概览 JSON Web Tokens(JWT)是用于保护无状态应用的事实上的标准。Spring Security 框架提供了集成 JWT 以保护 REST API 的方法。 本文将带你了解如何在 Spring Boot 应用中创建 SecretKey 实例来签发和验证 JWT。 2、项目设置 2.1、Maven 依赖 首先,在 pom.xml 中添加 spring-boot-starter-web、spring-boot-starter-security、spring-boot-starter-data-jpa 和 h2 数据库依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>3.2.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <version>3.2.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <version>3.2.3</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>2.2.224</version> </dependency> Spring Boot Starter Web 提供了用于构建 REST API 的 API。Spring Boot Starter Security 用于提供身份认证和授权。h2 是一个内存数据库,方便快速开发。 然后,还要在 pom.xml 中添加 jjwt-api、jjwt-impl 和 jjwt-jackson 依赖: <dependency> <groupId>io.

从 Spring Security 5 迁移到 Spring Security 6/Spring Boot 3

1、概览 Spring Security 6 有几处重大变化,包括删除了一些类和已废弃的方法,并引入了一些新方法。 从 Spring Security 5 迁移到 Spring Security 6 可以在不破坏现有代码的情况下逐步完成。此外,还可以使用 OpenRewrite 等第三方插件来促进向最新版本的迁移。 本文将带你了解如何把 Spring Security 5 的现有应用迁移到 Spring Security 6(替换过时的方法,并利用 Lambda DSL 简化配置。此外,还利用 OpenRewrite 加快迁移速度)。 2、Spring Security 和 Spring Boot 版本 Spring Boot 基于 Spring 框架,各版本的 Spring Boot 使用最新版本的 Spring 框架。Spring Boot 2 默认使用 Spring Security 5,而 Spring Boot 3 使用 Spring Security 6。 要在 Spring Boot 应用中使用 Spring Security,首先需要在 pom.xml 中添加 spring-boot-starter-security 依赖。 可以在 pom.xml 的 properties 部分 指定所需的版本,从而覆盖默认的 Spring Security 版本 :

Spring Security 配置 Basic Authentication

1、概览 本文将带你了解如何通过 Spring Security 提供的 Basic Authentication 机制来保护 MVC 应用。 2、Spring Security 配置 使用 Java 配置来配置 Spring Security: @Configuration @EnableWebSecurity public class CustomWebSecurityConfigurerAdapter { @Autowired private RestAuthenticationEntryPoint authenticationEntryPoint; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("user1") .password(passwordEncoder().encode("user1Pass")) .authorities("ROLE_USER"); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(expressionInterceptUrlRegistry -> expressionInterceptUrlRegistry.requestMatchers("/securityNone").permitAll() .anyRequest().authenticated()) .httpBasic(httpSecurityHttpBasicConfigurer -> httpSecurityHttpBasicConfigurer.authenticationEntryPoint(authenticationEntryPoint)); http.addFilterAfter(new CustomFilter(), BasicAuthenticationFilter.class); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } 如上,在 SecurityFilterChain Bean 中使用 httpBasic() 来定义 Basic Authentication。

Spring Security 设置 Authentication Provider

1、概览 本文将带你了解如何在 Spring Security 中设置 Authentication Provider,相比于使用简单的 UserDetailsService 的标准方案,这样可以提供额外的灵活性。 2、Authentication Provider Spring Security 提供了多种执行身份认证的选项。这些选项遵循一个简单的契约;一个 AuthenticationProvider 处理一个身份认证请求,并返回一个带有完整凭证的认证对象。 最常见的标准实现是 DaoAuthenticationProvider,它从一个简单的 UserDetailsService(只读)中获取用户详细信息。这个 Service 只能通过用户名检索完整的用户实体,这在大多数情况下已足够。 更多的自定义场景仍需要访问完整的认证请求才能执行身份验证流程。例如,在对某些外部第三方服务进行身份验证时,身份认证请求中的 username 和 password 都是必要的。 对于这些更高级的场景,需要定义一个自定义的 Authentication Provider: @Component public class CustomAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String name = authentication.getName(); String password = authentication.getCredentials().toString(); if (shouldAuthenticateAgainstThirdPartySystem()) { // 使用凭证并对第三方系统进行身份认证 return new UsernamePasswordAuthenticationToken( name, password, new ArrayList<>()); } else { return null; } } @Override public boolean supports(Class<?

Spring Security 控制 Session

1、概览 本文将带你了解如何在 Spring Security 中配置 Session 超时、Session 并发以及其他高级的 Session 安全设置。 2、何时创建 Session? 可以精确控制 Session 的创建时间,以及 Spring Security 与 Session 的交互方式: always:如果 Session 不存在,则会创建一个 Session。 ifRequired:仅在需要时才创建 Session(默认值)。 never:框架不会自己创建 Session,但如果 Session 已经存在,则会使用该 Session。 stateless:Spring Security 不会创建或使用 Session。 <http create-session="ifRequired">...</http> Java 配置如下: @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) return http.build(); } 注意,该配置只控制 Spring Security 的行为,而不是整个应用。如果指定 Spring Security 不创建 Session,它就不会创建 Session,但是应用可能会创建 Session! 默认情况下,Spring Security 会在需要时创建一个 Session,即 ifRequired。 对于无状态应用,never 选项将确保 Spring Security 本身不会创建任何 Session。但如果应用创建了 Session,Spring Security 就会使用它。