Spring Security
- 原理
Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它是用于保护基于Spring的应用程序的实际标准。
Spring Security是一个框架,致力于为Java应用程序提供身份验证和授权。与所有Spring项目一样,Spring Security的真正强大之处在于可以轻松扩展以满足自定义要求
Spring Security的体系结构旨在将身份验证与授权分开,并具有策略和扩展点。
1.身份验证
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}
authenticate()方法中的三件事之一:
- 如果可以验证输入是否代表有效的委托人,则返回Authentication(通常为authenticated=true)。
- AuthenticationException如果它认为输入代表无效的主体,则抛出一个。
- null如果无法决定,则返回。
//An AuthenticationProvider有点像an,AuthenticationManager但是它有一个额外的方法,允许调用者查询是否支持给定Authentication类型:
public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
/**
*
*/
boolean supports(Class<?> authentication);
}
@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
@Autowired
DataSource dataSource;
... // web stuff here
@Override
public void configure(AuthenticationManagerBuilder builder) {
builder.jdbcAuthentication().dataSource(dataSource).withUser("dave")
.password("secret").roles("USER");
}
}
2.访问控制
安全过滤器链 WebSecurityConfigurerAdapter
笔记:
5.1。认证方式
5.1.1。认证支持
5.1.2。密码储存
- DelegatingPasswordEncoder
-
确保使用当前密码存储建议对密码进行编码
-
允许以现代和旧式格式验证密码
-
允许将来升级编码
-
//.创建默认的DelegatingPasswordEncoder
PasswordEncoder passwordEncoder =
PasswordEncoderFactories.createDelegatingPasswordEncoder();
//创建自定义DelegatingPasswordEncoder
String idForEncode = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(idForEncode, new BCryptPasswordEncoder());
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("sha256", new StandardPasswordEncoder());
PasswordEncoder passwordEncoder =
new DelegatingPasswordEncoder(idForEncode, encoders);
- BCryptPasswordEncoder
- Argon2PasswordEncoder
- Pbkdf2PasswordEncoder
Spring Security 默认使用DelegatingPasswordEncoder。
@Bean
public static NoOpPasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
Spring为防止 跨站请求伪造(CSRF)
CSRF攻击之所以可能是因为受害者网站的HTTP请求与攻击者网站的请求完全相同。这意味着无法拒绝来自邪恶网站的请求并允许来自银行网站的请求。为了防御CSRF攻击,我们需要确保恶意站点无法提供请求中的某些内容,因此我们可以区分这两个请求。
Spring提供了两种机制来防御CSRF攻击:
- Specifying the SameSite Attribute on your session cookieSameSite属性
同步器令牌模式
该解决方案是为了确保每个HTTP请求除了我们的会话cookie外,还必须在HTTP请求中包含一个安全的,随机生成的值,称为CSRF令牌。
提交HTTP请求时,服务器必须查找预期的CSRF令牌,并将其与HTTP请求中的实际CSRF令牌进行比较。如果值不匹配,则应拒绝HTTP请求。
让我们看一下使用同步令牌模式时示例将如何变化。假设实际的CSRF令牌必须位于名为的HTTP参数中_csrf
。
通常建议将该SameSite属性用作深度防御,而不是针对CSRF攻击的唯一防护。
-
spring-security-core.jar
该模块包含核心身份验证和访问控制类和接口,远程支持和基本配置API。使用Spring Security的任何应用程序都需要它。它支持独立的应用程序,远程客户端,方法(服务层)安全性和JDBC用户配置。
org.springframework.security.core
org.springframework.security.access
org.springframework.security.authentication
org.springframework.security.provisioning -
网络- spring-security-web.jar
该模块包含过滤器和相关的Web安全基础结构代码。它包含任何与Servlet API相关的内容。如果需要Spring Security Web认证服务和基于URL的访问控制 -
spring-security-config.jar
该模块包含安全名称空间解析代码和Java配置代码。如果将Spring Security XML名称空间用于配置或Spring Security的Java Configuration支持,则需要它。
LDAP- spring-security-ldap.jar
此模块提供LDAP身份验证和供应代码。如果您需要使用LDAP认证或管理LDAP用户条目,则 -
此模块提供LDAP身份验证和供应代码。如果您需要使用LDAP认证或管理LDAP用户条目,
spring-security-oauth2-core.jar包含为OAuth 2.0授权框架和OpenID Connect Core 1.0提供支持的核心类和接口。使用OAuth 2.0或OpenID Connect Core 1.0的应用程序(例如客户端,资源服务器和授权服务器)需要它。 -
OAuth 2.0客户端- spring-security-oauth2-client.jar
spring-security-oauth2-client.jar包含Spring Security对OAuth 2.0授权框架和OpenID Connect Core 1.0的客户端支持。使用OAuth 2.0登录或OAuth客户端支持的应用程序需要使用它 -
spring-security-oauth2-jose.jar包含Spring Security对JOSE(JavaScript对象签名和加密)框架的支持。
- JSON Web令牌(JWT)
- JSON Web签名(JWS)
- JSON Web加密(JWE)
- JSON Web密钥(JWK)
-
OAuth 2.0资源服务器- spring-security-oauth2-resource-server.jar
spring-security-oauth2-resource-server.jar包含Spring Security对OAuth 2.0资源服务器的支持。它用于通过OAuth 2.0承载令牌保护API。 -
ACL- spring-security-acl.jar
该模块包含专门的域对象ACL实现。它用于将安全性应用于应用程序中的特定域对象实例 -
CAS — spring-security-cas.jar
该模块包含Spring Security的CAS客户端集成。如果要对CAS单点登录服务器使用Spring Security Web认证,则应该使用它。 -
OpenID — spring-security-openid.jar
该模块包含OpenID Web身份验证支持。它用于根据外部OpenID服务器对用户进行身份验证。顶级软件包是org.springframework.security.openid。它需要OpenID4Java。
Servlet应用
Spring Security通过使用标准Servlet与Servlet容器集成Filter。这意味着它可以与在Servlet容器中运行的任何应用程序一起使用。
Servlet安全性:大局
“ 身份验证”,“ 授权”和“防止利用漏洞”部分中建立了这种高级理解。
image.pngFilterChain
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// do something before the rest of the application
chain.doFilter(request, response); // invoke the rest of the application
// do something after the rest of the application
}
DelegatingFilterProxy
DelegatingFilterProxy可以通过标准Servlet容器机制进行注册,但是将所有工作委托给实现的Spring Bean Filter。
image.png
另一个好处DelegatingFilterProxy是,它允许延迟查找Filterbean实例。这很重要,因为容器需要Filter在容器启动之前注册实例。但是,Spring通常使用a ContextLoaderListener来加载Spring Bean,直到Filter需要注册实例之后才能完成。
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { // Lazily get Filter that was registered as a Spring Bean // For the example in [DelegatingFilterProxy](https://docs.spring.io/spring-security/site/docs/5.3.2.BUILD-SNAPSHOT/reference/html5/#servlet-delegatingfilterproxy-figure) `delegate` is an instance of *Bean Filter<sub>0</sub>* Filter delegate = getFilterBean(someBeanName); // delegate work to the Spring Bean delegate.doFilter(request, response); }
FilterChainProxy
image.png
Spring Security的Servlet支持包含在中FilterChainProxy
。 FilterChainProxy
是Filter
Spring Security提供的一种特殊功能,它允许Filter
通过委派许多实例SecurityFilterChain
。由于FilterChainProxy
是Bean,因此通常将其包装在DelegatingFilterProxy中。
SecurityFilterChain
SecurityFilterChain
由FilterChainProxy用于确定Filter
应对此请求调用哪些Spring Security 。
该保安过滤器中SecurityFilterChain
通常是豆类,但他们与注册FilterChainProxy
代替的DelegatingFilterProxy。 FilterChainProxy
直接向Servlet容器或DelegatingFilterProxy注册具有许多优点。首先,它为Spring Security的所有Servlet支持提供了一个起点。因此,如果您想对Spring Security的Servlet支持进行故障排除,则在其中添加调试点FilterChainProxy
是一个很好的起点。
其次,由于FilterChainProxy
对于Spring Security的使用至关重要,因此它可以执行不被视为可选任务。例如,它清除SecurityContext
以避免内存泄漏。它还使用Spring Security HttpFirewall
来保护应用程序免受某些类型的攻击。
另外,它在确定何时SecurityFilterChain
调用a时提供了更大的灵活性。在Servlet容器中,Filter
仅根据URL调用。但是,FilterChainProxy
可以HttpServletRequest
利用RequestMatcher
接口根据任何内容确定调用。
实际上,FilterChainProxy
可以用来确定SecurityFilterChain
应该使用哪个。如果您的应用程序可以为不同的片提供完全独立的配置。
9.5。安全过滤器
-
ChannelProcessingFilter
-
ConcurrentSessionFilter
-
WebAsyncManagerIntegrationFilter
-
SecurityContextPersistenceFilter
-
HeaderWriterFilter
-
CorsFilter
-
CsrfFilter
-
LogoutFilter
-
OAuth2AuthorizationRequestRedirectFilter
-
Saml2WebSsoAuthenticationRequestFilter
-
X509AuthenticationFilter
-
AbstractPreAuthenticatedProcessingFilter
-
CasAuthenticationFilter
-
OAuth2LoginAuthenticationFilter
-
Saml2WebSsoAuthenticationFilter
-
ConcurrentSessionFilter
-
OpenIDAuthenticationFilter
-
DefaultLoginPageGeneratingFilter
-
DefaultLogoutPageGeneratingFilter
-
BearerTokenAuthenticationFilter
-
RequestCacheAwareFilter
-
SecurityContextHolderAwareRequestFilter
-
JaasApiIntegrationFilter
-
RememberMeAuthenticationFilter
-
AnonymousAuthenticationFilter
-
OAuth2AuthorizationCodeGrantFilter
-
SessionManagementFilter
-
SwitchUserFilter
处理安全异常
在ExceptionTranslationFilter
允许的翻译AccessDeniedException
和AuthenticationException
到HTTP响应。
ExceptionTranslationFilter
作为安全过滤器之一插入到FilterChainProxy中。
-
1号
首先,
ExceptionTranslationFilter
调用FilterChain.doFilter(request, response)
将调用应用程序的其余部分。 -
[图片上传失败...(image-9e46a-1586791805902)] 如果用户未通过身份验证或为
AuthenticationException
,则Start Authentication.-
将
HttpServletRequest
保存在中RequestCache
。当用户成功验证身份后,将RequestCache
用于重播原始请求。 -
的
AuthenticationEntryPoint
用于从客户机请求的凭证。例如,它可能重定向到登录页面或发送WWW-Authenticate
标题。
-
3号
否则,如果是
AccessDeniedException
,则拒绝访问。将AccessDeniedHandler
被调用,以拒绝提手接近。
| |
如果应用程序未抛出AccessDeniedException
或AuthenticationException
,ExceptionTranslationFilter
则不执行任何操作
ExceptionTranslationFilter伪代码
try {
filterChain.doFilter(request, response);
} catch (AccessDeniedException | AuthenticationException e) {
if (!authenticated || e instanceof AuthenticationException) {
startAuthentication();
} else {
accessDenied();
}
}
| | 你可以从召回进展的Filter
小号即调用FilterChain.doFilter(request, response)
是等效的调用应用程序的其余部分。这意味着如果应用程序的另一部分(即FilterSecurityInterceptor
方法安全性)抛出AuthenticationException
或AccessDeniedException
,它将在此处被捕获和处理。 |
| | 如果用户未通过身份验证或为AuthenticationException
,则开始身份验证。 |
| | 否则,访问被拒绝 |