[译]Spring Security 面试问题

本面试准备指南将讨论一些常见的 Spring Security 面试问题。无论您是准备面试还是只是想增强对 Spring Security 的了解,这些问题都将帮助您理解关键概念并指导您设计常见安全问题的解决方案。

1. Spring Security 的核心特性是什么?

Spring Security 提供的两个最突出的功能是身份验证和授权。这些功能在确保应用程序的安全性方面发挥着至关重要的作用。然而,Spring Security 超越了身份验证和授权,还提供了额外的功能来防止漏洞利用并与其他框架集成。

1.1.验证

身份验证是验证尝试访问应用程序的用户身份的过程。 Spring Security 提供多种身份验证方法(基于表单的身份验证、HTTP 基本身份验证、OAuth2、Siteminder、OpenID Connect、LDAP、JDBC 等),允许应用程序使用各种方法对用户进行身份验证。

它还支持自定义,当默认选项不满足要求时,可以实现自定义的身份验证机制。

1.2.授权

授权是向经过身份验证的用户或实体授予许可或权利的过程。用户或实体成功通过身份验证后,授权将决定他们可以在应用程序中访问哪些操作或资源。 Spring Security 为开发人员提供了多种方法来实现授权并控制用户对应用程序不同部分的访问。以下是一些常见的方法:

1.3.防止漏洞利用

Spring Security 提供了多种功能来防范常见的 Web 应用程序安全漏洞。一些显着的功能包括:

1.4.集成

Spring Security 与其他框架和库无缝集成,以增强应用程序的安全性。一些关键的集成是:

有关 Spring Security 功能的更详细信息,请参阅官方文档

2.解释一下 Spring Security 的核心组件?

当谈到 Spring Security 时,几个核心组件在为 Java 应用程序提供安全功能方面发挥着至关重要的作用。这些组件协同工作以确保强大的身份验证、授权和其他安全功能。

2.1.委托过滤代理

DelegatingFilterProxy是 Spring 框架提供的一个特殊的 Servlet Filter。它充当处理安全相关请求的入口点。当收到请求时,DelegatingFilterProxy 将请求委托给 Spring FilterChainProxy bean 进行进一步处理(springSecurityFilterChain bean)。 FilterChainProxy 利用SecurityFilterChain 来确定为当前请求调用的适当的过滤器集。

2.2.过滤器链代理

FilterChainProxy 根据传入请求的 URL 模式和定义的安全配置确定要应用哪些过滤器。它根据配置的安全规则评估请求并选择适当的过滤器链(使用@EnableWebSecurityFilterChainProxy 自动创建为 bean。它包装实际的安全过滤器链并充当处理请求的委托)。

2.3.安全过滤链

当收到请求时,FilterChainProxy 会找到相应的 SecurityFilterChain 并执行该链中的过滤器列表。每个过滤器根据应用程序的安全配置执行其指定的任务。过滤器可以修改请求、执行身份验证检查、验证权限或处理与会话相关的操作。

Spring Security 中的一些重要安全过滤器包括:

一旦请求到达SecurityFilterChain内注册的过滤器,相应的过滤器就会将请求委托给其他 bean 来执行相应的任务。例如,AuthenticationProcessingFilter 准备 Authentication 实例并将其委托给 AuthenticationManager 进行身份验证流程。

img

2.4.认证管理器

AuthenticationManager 负责对用户进行身份验证。它有一个名为 authenticate () 的方法,该方法将 Authentication 实例作为参数。 authenticate () 方法负责验证所提供的凭据(在 AuthenticationProvider 的适当实现的帮助下),并在身份验证成功时返回经过身份验证的 Authentication 对象。

默认情况下,Spring Security 提供了一个名为 ProviderManagerAuthenticationManager 接口的实现。 ProviderManager 将身份验证过程委托给 AuthenticationProvider 实例列表。

2.5.认证提供者

AuthenticationProvider 负责验证特定类型的凭证或身份验证机制。它定义了针对特定源(例如用户数据库、外部身份验证服务或任何其他自定义身份验证机制)执行身份验证的合同。

当应用程序中使用多种身份验证机制时,可以配置多个 AuthenticationProvider 实例来单独处理每种机制。

更多信息请参考官方文档

3. Spring Security 如何处理用户认证?

在较高级别上,Spring Security 通过一系列步骤处理用户身份验证。大多数步骤对于各种身份验证都是通用的,但很少有身份验证流程需要特定步骤。

以下步骤演示了基于表单登录的身份验证,其中用户在请求中输入用户名/密码组合。

img

4. AuthenticationManager 如何确定合适的 AuthenticationProvider?

在身份验证过程中,AuthenticationManager 接收代表用户凭据的 Authentication 对象。 AuthenticationManager 循环访问每个 AuthenticationProvider 并调用它们的 supports(Class<?> authentication) 方法来确定提供程序是否支持特定类型的 Authentication 对象。每个 AuthenticationProvider 都实现此方法,并且通常检查提供程序是否可以根据身份验证对象的类处理身份验证请求。

这是 ProviderManager 源代码中的代码片段,它是 AuthenticationManager 的默认实现:

public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Class<? extends Authentication> toTest = authentication.getClass();
// .......
for (AuthenticationProvider provider : getProviders()) {
if (!provider.supports(toTest)) {
continue;
}
// ......
}

一旦找到支持给定身份验证对象的 AuthenticationProviderAuthenticationManager 就会调用提供程序的 authenticate(Authentication authentication) 方法。此方法执行特定于该提供程序的身份验证逻辑,例如根据用户数据库或外部身份验证服务验证凭据。

5. Spring Security 如何处理用户授权?

在较高的层面上,Spring Security 通过一个涉及多个组件协同工作的过程来处理用户授权。

img

以下是该过程的概述。

6.什么是密码编码器?默认编码器是什么?

PasswordEncoder 是一个用于使用 encode()matches()方法对密码进行编码和验证的接口。它负责获取用户的密码,应用单向哈希算法,并安全地存储哈希密码。当用户尝试登录时,输入的密码会使用相同的算法再次进行哈希处理,并将生成的哈希值与存储的哈希密码进行比较以进行身份 验证。

默认密码编码器是 BCryptPasswordEncoder。 BCrypt 是一种广泛使用的安全哈希算法,它结合了加盐和成本因素,以防止各种类型的攻击,包括暴力攻击。 BCryptPasswordEncoder 是密码存储的不错选择,因为它提供了高级别的安全性。

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

对于自定义要求,我们还可以配置自定义密码编码器。

实现 PasswordEncoder 接口

创建一个实现 PasswordEncoder 接口的类。此类将提供编码和验证密码的实现。

public class CustomPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword)
// Implement your password encoding logic here
// Return the encoded password as a String
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
// Implement your password verification logic here
// Compare the rawPassword with the encodedPassword and return true or false
}
}

配置自定义密码编码器

在 Spring Security 配置中,我们可以通过定义 PasswordEncoder bean 来指定自定义密码编码器的使用。 Spring Security 将使用这个 bean 进行密码编码和验证。

@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new CustomPasswordEncoder();
}
// Other security configuration code
}

7. 如何在非 Spring boot 应用程序中启用 Spring 安全性?

当谈到在非 Spring Boot 应用程序中启用 Spring Security 时,我们可以采取几种方法。让我们探讨两种标准方法:

使用 AbstractSecurityWebApplicationInitializer 进行基于 Java 的配置

在 Java 配置中,我们可以通过扩展 AbstractSecurityWebApplicationInitializer 类并选择性地重写其方法来配置 DelegatingFilterProxy 并将其与 springSecurityFilterChain bean 关联来启用 Spring Security。它避免在 web.xml 文件中写入 servlet-filter 配置。

我们可以在 SecurityConfig.java 中定义自定义安全 bean。

public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
public SpringSecurityInitializer() {
super(SecurityConfig.class);
}
}

基于 XML 的配置

在 XML 配置中,我们需要显式定义 DelegatingFilterProxy bean 并使用过滤器名称将其映射到 springSecurityFilterChain bean。此链接通常在 web.xml 文件中完成:

<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>ERROR</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>

8. 如何在 Spring boot 应用程序中启用 Spring 安全性?

如果我们使用 Spring Boot,启用 Spring Security 就非常简单。我们需要做的就是将 Spring Security starter 添加到项目的依赖项中,默认情况下自动配置将可用。这是因为当 Spring Security 位于类路径中时,WebSecurityEnablerConfiguration 会自动为我们激活 @EnableWebSecurity 注解。

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

9. Spring Security 中@EnableWebSecurity 的用途是什么?

@EnableWebSecurity 注解用于启用应用程序的 Web 安全性。当此注释添加到配置类时,表示该类将提供必要的配置和设置来保护 Web 应用程序。

在非 Spring boot 应用程序中,@EnableWebSecurity 注释除了提供开发人员编写的自定义配置 bean 之外,还会隐式执行以下任务。

在 Spring boot 应用程序中,使用 @EnableWebSecurity 注释是可选的。 Spring boot 安全自动配置提供了与使用@EnableWebSecurity 注释几乎相同的功能。

当在 Spring boot 应用程序中使用 @EnableWebSecurity 时,默认的自动配置会后退,并提供的配置优先。

@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring()
.requestMatchers("/resources/**");
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests()
.requestMatchers("/public/**").permitAll()
.anyRequest().hasRole("USER")
.and()
.formLogin().permitAll();
return http.build();
}
// Possibly more bean methods ...
}

10. Spring Security 中的角色和权限有什么区别?

在 Spring Security 中,角色和权限都用于定义和管理用户权限。然而,两者之间有一个微妙的区别:

11.如何使用注解实现方法安全?

除了 URL 级别的安全性之外,Spring Security 还支持方法级别的安全性。要在 Spring Security 中使用注解实现方法级安全性,我们可以使用@EnableMethodSecurity 注解任何@Configuration 类。

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
//..
}

现在我们可以通过@Secured、@PreAuthorize、@PostAuthorize、@PreFilter 和@PostFilter 注解来授权方法调用,包括输入参数和返回值。

在以下示例中, deleteProduct 方法使用 @PreAuthorize 注释进行保护,表达式 hasRole('ADMIN') 确保只有具有“ADMIN”角色的用户才能调用此方法。

@PreAuthorize("hasRole('ADMIN')")
public void deleteProduct(Long productId) {
// Method logic for deleting a product
}

默认情况下,Spring boot 中方法安全性是禁用的。

12.什么是基本身份验证?如何实施?

基本身份验证是一种简单的身份验证机制,其中客户端在每个请求的 HTTP 标头中包含用户名和密码(凭据以“ username:password ”格式发送,然后在包含之前进行 Base64 编码在 Authorization 标头中)。然后,服务器验证凭据,如果正确,则授予对所请求资源的访问权限。

为了在 Spring Security 中启用基本身份验证,我们使用 *httpBasic*() 方法。

@Bean
public SecurityFilterChain securityFilterChain (HttpSecurity http) throws Exception {
http.authorizeHttpRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
return http.build();
}

13.什么是 JWT 认证?如何实施?

JWT(JSON Web Token)身份验证是一种流行的身份验证机制,它使用基于 JSON 的令牌在各方之间安全地传输身份验证和授权信息。它支持无状态身份验证,并且无需在服务器端存储会话。

img

要在 Spring Security 中实现 JWT 身份验证,我们可以按照以下步骤操作:

有关实现细节的更多信息,请阅读 Spring Security 中的 JWT 身份验证一文。

14. 如何实现 OAuth2 安全性?

OAuth2 是一个授权框架,允许应用程序获得对用户帐户的有限访问权限。它涉及多个组件,包括授权服务器和资源服务器。授权服务器处理身份验证并颁发访问令牌,而资源服务器托管受保护的资源并验证访问令牌。

实现 OAuth2 安全性,您需要配置授权服务器和资源服务器

授权服务器

授权服务器负责对用户进行身份验证并颁发访问令牌。在 Spring Security 中,我们可以使用 AuthorizationServerConfigurerAdapter 类来配置授权服务器。

以下类设置授权服务器,定义安全约束,并配置可以访问服务器的客户端以获取访问令牌以进行身份 验证和授权。

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {
@Autowired
private BCryptPasswordEncoder passwordEncoder;
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
.allowFormAuthenticationForClients();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client-id")
.secret("client-secret")
.authorizedGrantTypes("authorization_code", "password", "refresh_token")
.scopes("read", "write")
.accessTokenValiditySeconds(3600)
.refreshTokenValiditySeconds(86400);
}
}

资源服务器

资源服务器托管受保护的资源并验证访问令牌。在 Spring Security 中,我们可以使用 ResourceServerConfigurerAdapter 类来配置资源服务器。

在以下示例中,OAuth2ResourceServerConfig 通过指定不同 API 端点的访问规则来配置资源服务器。它允许不受限制地访问公共资源,同时要求对私人访问进行身份验证。

@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.antMatchers("/api/private/**").authenticated();
}
}

资源服务器需要验证访问令牌,以确保它是由受信任的授权服务器颁发的,并且没有过期或被篡改。

一种常见的方法是使用 Spring Security 提供的 RemoteTokenServices 类。资源服务器向授权服务器的 /oauth/check_token 端点发出请求,并将访问令牌作为参数传递。

@Bean
public ResourceServerTokenServices tokenService() {
RemoteTokenServices tokenServices = new RemoteTokenServices();
tokenServices.setClientId("client-id");
tokenServices.setClientSecret("client-secret");
tokenServices.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token");
return tokenServices;
}

15. Spring Security 中的 CSRF 保护是什么?如何实施?

CSRF(跨站点请求伪造)保护是一种安全机制,可防止攻击者利用用户和网站之间的信任。它可以防范 CSRF 攻击,即攻击者在用户不知情或未同意的情况下诱骗用户的浏览器在网站上执行不需要的操作。

要在 Spring Security 中实现 CSRF 保护,我们可以按照以下步骤操作:

默认情况下,Spring Security 自动启用 CSRF 保护。它将 CSRF 令牌添加到表单中并将其包含在后续请求中。

我们可以使用 csrf() 方法在 Spring Security 中配置/自定义 CSRF 保护。

@Configuration
public class SecurityWithCsrfCookieConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
return http.build();
}
}

在上面的示例中,我们将 CSRF 保护配置为使用 CookieCsrfTokenRepository 并通过设置 withHttpOnlyFalse() 确保 JavaScript 可以访问 CSRF 令牌。我们可以根据我们的需求选择不同的 CsrfTokenRepository 实现。

16. 什么是 CORS 以及 Spring Security 中如何处理它?

CORS(跨源资源共享)是 Web 浏览器强制执行的一种安全机制,用于限制跨源 HTTP 请求。它允许服务器指定允许哪些源(域)访问其资源。

在 Spring Security 中,有两种方法可以在我们的应用程序中配置 CORS:

全局配置

我们可以通过创建 CorsConfigurationSource 类的 bean 来全局配置 CORS 支持。在此示例中,我们将 CORS 策略配置为允许来自指定源(本例中为 http://localhost:8081 )的跨源请求。

@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.addAllowedOrigin("http://localhost:8081");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}

处理程序方法特定的配置

如果我们只需要特定端点的 CORS,我们可以在方法级别使用 @CrossOrigin 注释。这允许我们指定允许的源、HTTP 方法和其他配置。

在此示例中, /api/resource 端点仅允许使用指定 HTTP 方法来自 http://example.com 的跨源请求。

@RestController
public class MyController {
@GetMapping("/api/resource")
@CrossOrigin(origins = "http://example.com", methods = {RequestMethod.GET, RequestMethod.POST})
public String getResource() {
//...
}
}

17.解释一下基于会话的身份验证?

基于会话的身份验证是 Web 应用程序中管理用户身份验证的常用方法。它涉及使用会话和 cookie 来维护身份验证状态并识别经过身份验证的用户。

img

基于会话的身份验证的工作原理如下:

18. 如何防止暴力破解?

防止暴力攻击涉及实施一些措施,使攻击者难以通过重复登录尝试猜测有效凭据。

以下是我们可以用来降低暴力攻击风险的一些策略:

19. Spring Security 中如何处理注销?

在基于会话的身份验证中,注销涉及销毁会话对象并删除用户浏览器中的会话 cookie。这可以通过配置 HttpSecurity 来实现,如下所示:

http
// Other security configurations...
.logout()
.invalidateHttpSession(true) / Invalidate the user's HttpSession
.deleteCookies("JSESSIONID") / Remove the session cookie
.logoutSuccessUrl("/login?logout") / Redirect to the logout success URL
.permitAll(); / Allow anyone to access the logout URL

20. 迁移过程中如何支持多个密码编码器?

要在 Spring Security 迁移期间支持多个密码编码器,您可以使用 Spring Security 提供的 DelegatingPasswordEncoder。 DelegatingPasswordEncoder 允许您配置多个密码编码器,并将每个编码器与标识符或“id”相关联。

@Bean
public PasswordEncoder passwordEncoder() {
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put("bcrypt", new BCryptPasswordEncoder());
encoders.put("custom", new CustomPasswordEncoder()); / Replace with your custom encoder
return new DelegatingPasswordEncoder("bcrypt", encoders);
}

在上面的例子中,我们配置了两个密码编码器:

DelegatingPasswordEncoder 使用默认编码器 ID(“bcrypt”)和编码器映射进行初始化。在身份验证过程中,Spring Security 将根据编码密码的前缀或提供的编码器 ID 确定适当的编码器。

21.保护 REST-API 的最佳实践?

实施 REST API 安全性涉及多种注意事项,以保护 API 免受未经授权的访问并确保数据完整性。

22. Spring Security 如何与 Mobile App Security 配合使用?

Spring Security 能够与移动应用程序安全性无缝集成,提供强大的身份验证和授权功能。

一种流行的方法是基于令牌的安全性,其中移动应用程序向服务器发送身份验证请求并获取令牌(例如 JWT)作为响应。随后,该令牌将包含在所有后续 API 请求中,以用作授权机制。

结论

这本常见 Spring Security 面试问题和答案的综合指南探讨了身份验证、授权和 Spring Security 的各种组件等关键概念。我们深入研究了密码编码、请求匹配、方法安全注释以及与其他框架的集成等主题。通过熟悉这些面试问题及其答案,您可以在面试期间自信地处理 Spring Security 相关的讨论。

快乐学习!

原文链接:Spring Security Interview Questions

订阅文章

订阅更新,不错过后续文章

直接通过 RSS 和 Telegram 订阅本站更新。

订阅 RSS关注 Telegram

分享文章

如果这篇有帮助,可以顺手转发

直接分享给同事、朋友,或者发到你的社交平台。

分享到 X 分享到 Telegram 邮件分享
[译]关于 HTTP 您需要了解的一切
React 入门:初始化应用的两种方法