- 原理
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安全性:大局
“ 身份验证”,“ 授权”和“防止利用漏洞”部分中建立了这种高级理解。
FilterChain
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。
另一个好处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
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中。
-
ExceptionTranslationFilter
调用FilterChain.doFilter(request, response)
将调用应用程序的其余部分。 -
[图片上传失败...(image-9e46a-1586791805902)] 如果用户未通过身份验证或为
AuthenticationException
,则Start Authentication.将
HttpServletRequest
保存在中RequestCache
。当用户成功验证身份后,将RequestCache
用于重播原始请求。的
AuthenticationEntryPoint
用于从客户机请求的凭证。例如,它可能重定向到登录页面或发送WWW-Authenticate
标题。
-
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
,则开始身份验证。 |
| | 否则,访问被拒绝 |