您现在的位置是:首页 >其他 >Spring Security实战(七)—— 跨域请求伪造的防护及单点登录网站首页其他
Spring Security实战(七)—— 跨域请求伪造的防护及单点登录
一、CSRF
CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种常见的网络攻击方式,它利用用户在已登录网站的情况下,通过伪造请求(例如在另一个网站中的图片或链接中),向该网站发送恶意请求,从而在用户不知情的情况下执行某些操作,例如修改密码、发送私信等。
为了防止 CSRF 攻击,您可以采取以下措施:
-
验证请求来源:在服务器端对请求来源进行验证,如果请求来源与预期不一致,可以拒绝该请求。例如,在 Spring Security 中,可以通过启用 CSRF 防护来自动验证请求来源。
-
使用随机的 CSRF 令牌:在每个表单或请求中包含一个随机的 CSRF 令牌,服务器端对该令牌进行验证,如果令牌与预期不一致,可以拒绝该请求。例如,在 Spring Security 中,可以使用 CSRF Token 来实现此功能。
-
限制敏感操作的访问:对于某些敏感操作,例如修改密码、发送私信等,可以限制只有已登录用户才能进行操作,或者对该操作进行二次验证,例如要求用户输入密码或短信验证码。
-
避免使用 GET 请求进行敏感操作:GET 请求通常被用来获取资源,而 POST 请求通常被用来提交数据。如果使用 GET 请求进行敏感操作,可能会因为浏览器或代理服务器缓存请求结果,导致攻击者可以通过预加载的缓存来伪造请求。
二、使用Spring Security防御CSRF攻击
CSRF攻击完全是基于浏览器进行的,如果我们的系统前端并非在浏览器中运作,就应当关闭CSRF。
(1)添加 CSRF Token:Spring Security 可以自动生成 CSRF Token,并将其添加到所有的表单请求和非 GET 请求中。在服务器端进行验证,如果 Token 不匹配,则拒绝该请求。可以通过以下代码配置:
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
(2)SameSite Cookie:SameSite Cookie 是一种可以限制 Cookie 跨站点访问的技术,可以有效地防止 CSRF 攻击。Spring Security 支持配置 SameSite Cookie,可以通过以下代码配置:
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.requireCsrfProtectionMatcher(new RequestMatcher() {
private final Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
private final RegexRequestMatcher unprotectedMatcher = new RegexRequestMatcher("/unprotected", null);
@Override
public boolean matches(HttpServletRequest request) {
if (allowedMethods.matcher(request.getMethod()).matches()) {
return false;
}
if (unprotectedMatcher.matches(request)) {
return false;
}
return true;
}
});
http
.headers()
.httpStrictTransportSecurity()
.includeSubDomains(true)
.maxAgeInSeconds(31536000)
.and()
.xssProtection()
.block(true)
.and()
.contentTypeOptions()
.nosniff()
.and()
.cacheControl()
.disable();
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http
.authorizeRequests()
.antMatchers("/unprotected")
.permitAll()
.anyRequest()
.authenticated();
http
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint());
}
(3)验证请求来源:Spring Security 提供了 CsrfFilter
过滤器,该过滤器可以验证请求来源是否与当前页面的源相同。如果请求来源与当前页面的源不同,则可能是 CSRF 攻击,应该拒绝该请求。可以通过以下代码启用 CsrfFilter
:
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.requireCsrfProtectionMatcher(new RequestMatcher() {
private final Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
private final RegexRequestMatcher unprotectedMatcher = new RegexRequestMatcher("/unprotected", null);
@Override
public boolean matches(HttpServletRequest request) {
if (allowedMethods.matcher(request.getMethod()).matches()) {
return false;
}
if (unprotectedMatcher.matches(request)) {
return false;
}
return true;
}
});
}
(4)添加验证码
这种方式是在表单中添加一个验证码字段,要求用户在提交表单之前输入验证码。这样可以防止 CSRF 攻击,因为攻击者无法知道正确的验证码。可以通过自定义过滤器实现。例如:
public class CaptchaFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 如果是登录请求,需要检查验证码
if ("/login".equals(request.getRequestURI()) && "POST".equalsIgnoreCase(request.getMethod())) {
String code = request.getParameter("code"); // 获取用户输入的验证码
String sessionCode = (String) request.getSession().getAttribute("code"); // 获取正确的验证码
if (!StringUtils.isEmpty(code) && code.equals(sessionCode)) {
filterChain.doFilter(request, response); // 验证码正确,继续处理请求
return;
} else {
response.sendRedirect("/login?error=invalidCode"); // 验证码不正确,跳转回登录页
return;
}
}
filterChain.doFilter(request, response); // 不是登录请求,直接继续处理
}
}
然后再spring security的配置中添加:
http.addFilterBefore(new CaptchaFilter(), UsernamePasswordAuthenticationFilter.class);
三、单点登录
单点登录(Single Sign-On,简称 SSO)是一种身份认证机制,允许用户使用一组凭证(如用户名和密码)登录到多个应用程序或系统,而无需多次输入凭证。
在传统的身份认证机制中,每个应用程序或系统都要求用户输入一次用户名和密码。但是,对于使用多个应用程序或系统的用户来说,这样的流程很麻烦和不必要。使用单点登录可以让用户只需登录一次,就可以在多个应用程序或系统中使用,提高用户的使用体验和工作效率。
单点登录通常由一个认证中心(Authentication Server)来实现。用户在认证中心进行身份验证,并获得一个令牌(Token)。用户访问其他应用程序或系统时,令牌将被发送给该应用程序或系统,以进行身份验证。如果令牌有效,则用户被授权访问该应用程序或系统,否则用户需要重新登录。
使用单点登录可以提高安全性,因为用户只需要输入凭证一次,减少了凭证泄露的风险;也可以降低开发和维护成本,因为多个应用程序或系统可以共享认证机制和用户信息。
四、CAS
CAS (Central Authentication Service) 是一种开源的单点登录协议和实现,也是一种常见的单点登录解决方案。CAS 由耶鲁大学开发,是基于 HTTP 协议实现的中心化身份认证系统。
CAS 通过一个统一的认证中心(CAS Server)来管理用户的身份认证信息。用户在第一次访问需要进行身份认证的应用程序时,将被重定向到 CAS Server 进行身份认证。如果身份认证成功,CAS Server 会向用户颁发一个票据(Ticket),同时在本地保存一个 Session,并将票据返回给用户的浏览器。用户在访问其他需要身份认证的应用程序时,将使用浏览器中保存的票据向 CAS Server 进行认证。如果票据有效,则用户被授权访问该应用程序。
1. CAS 的特点包括:
- 开源:CAS 是一种开源的单点登录解决方案,可以自由下载、修改和使用。
- 安全:CAS 使用加密算法来保证用户的凭证安全,同时支持多种身份认证方式,如用户名密码、LDAP、Active Directory、OAuth 等。
- 可扩展:CAS 支持多种认证协议,如 CAS、OAuth、OpenID 等,可以与不同的应用程序和系统集成。
- 易于部署:CAS 可以与不同的 Web 容器和应用程序集成,同时提供了多种客户端库,便于开发人员集成 CAS。
- 可靠性:CAS 支持多种负载均衡和故障转移机制,可以保证高可用性和可靠性。
总之,CAS 是一种成熟、稳定、安全、可扩展、易于部署和集成的单点登录解决方案。
CAS由CAS Server和CAS Client两部分组成。CAS Server是一个单点的验证服务,CAS Client是共享CAS Server登录态的客户端。例如:阿里巴巴旗下的淘宝,天猫,在CAS结构中都属于客户端。
2. 三个术语:TGT,TGC,ST。
- TGT (Ticket Granting Ticket) 是一种用于表示用户身份的票据,用于表示用户在 CAS Server 中的身份认证信息,它是 CAS Server 中唯一的一个票据。在用户进行身份认证成功后,CAS Server 会向用户的浏览器颁发一个 TGT,同时在服务器端保存一份,用于后续的票据颁发和验证。
- TGC (Ticket Granting Cookie) 是一个用于保存 TGT 的 Cookie,当用户在 CAS Server 中进行身份认证成功后,CAS Server 会将 TGT 返回给用户的浏览器,并在浏览器中设置一个 TGC。TGC 的作用是用于在浏览器和 CAS Server 之间建立会话,并将 TGT 与浏览器关联起来,从而避免在每次请求时都需要重新进行身份认证。
- ST (Service Ticket) 是一种用于表示用户对某个应用程序的访问权限的票据,用于表示用户已经经过身份认证,并被授权访问某个应用程序。在用户访问某个需要进行身份认证的应用程序时,CAS Server 会向用户颁发一个 ST,用户可以使用 ST 向应用程序进行身份认证。在用户进行身份认证后,应用程序会将 ST 与 CAS Server 进行验证,从而确认用户的身份和授权信息。
3. CAS 单点登录的完整步骤如下:
- 用户访问某个需要进行身份认证的应用程序。
- 应用程序判断用户未登录,则跳转到 CAS Server 的登录页面,CAS Server 会向用户展示登录表单,要求用户输入用户名和密码进行身份认证。
- 用户输入用户名和密码进行身份认证。
- CAS Server 验证用户的身份信息是否正确,如果验证通过,则在服务器端生成一个 TGT,并将 TGT 返回给用户的浏览器,并在浏览器中设置一个 TGC(Ticket Granting Cookie),用于在浏览器和 CAS Server 之间建立会话,并将 TGT 与浏览器关联起来,从而避免在每次请求时都需要重新进行身份认证。
- 用户访问另一个需要进行身份认证的应用程序。
- 应用程序判断用户未登录,则跳转到 CAS Server 的登录页面,CAS Server 在浏览器中检查是否存在有效的 TGC,如果存在,则说明用户已经经过 CAS Server 的身份认证,并且已经具有了 TGT,此时 CAS Server 会向用户颁发一个 ST(Service Ticket),并将 ST 返回给用户的浏览器。
- 用户使用 ST 向应用程序进行身份认证。
- 应用程序将 ST 与 CAS Server 进行验证,从而确认用户的身份和授权信息,如果验证通过,则用户被认为已经登录了应用程序。
需要注意的是,当用户在 CAS Server 中进行身份认证成功后,CAS Server 会向用户颁发一个 TGT,同时在服务器端保存一份,用于后续的票据颁发和验证。在用户访问另一个需要进行身份认证的应用程序时,CAS Server 会向用户颁发一个 ST,用户可以使用 ST 向应用程序进行身份认证。在用户进行身份认证后,应用程序会将 ST 与 CAS Server 进行验证,从而确认用户的身份和授权信息。此外,为了提高安全性,CAS 还支持单点登出功能,即用户在一个应用程序中注销后,可以自动注销所有与 CAS Server 建立了信任关系的应用程序,避免用户在多个应用程序中反复注销。