将 AngularJS 与 SpringSecurity3.2 一起用于 CSRF
Posted
技术标签:
【中文标题】将 AngularJS 与 SpringSecurity3.2 一起用于 CSRF【英文标题】:Using AngularJS with SpringSecurity3.2 for CSRF 【发布时间】:2014-07-24 05:59:00 【问题描述】:AngularJS
index.html
<head>
<meta name="_csrf" content="$_csrf.token"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" content="$_csrf.headerName"/>
</head>
SpringSecurity 3.2
Spring 使用 HttpSessionCsrfTokenRepository,默认情况下 CSRF 的标头名称为 X-CSRF-TOKEN,但 Anuglar 约定是 X-XSRF-TOKEN
我想扩展 HttpSessionCsrfTokenRepository 并覆盖标头名称,但由于它被标记为 final 我最终实现了自定义令牌存储库。
@Component
public class CustomCsrfTokenRepository implements CsrfTokenRepository
public static final String CSRF_PARAMETER_NAME = "_csrf";
public static final String CSRF_HEADER_NAME = "X-XSRF-TOKEN";
private final Map<String, CsrfToken> tokenRepository = new ConcurrentHashMap<>();
public CustomCsrfTokenRepository()
log.info("Creating ", CustomCsrfTokenRepository.class.getSimpleName());
@Override
public CsrfToken generateToken(HttpServletRequest request)
return new DefaultCsrfToken(CSRF_HEADER_NAME, CSRF_PARAMETER_NAME, createNewToken());
@Override
public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response)
String key = getKey(request);
if (key == null)
return;
if (token == null)
tokenRepository.remove(key);
else
tokenRepository.put(key, token);
@Override
public CsrfToken loadToken(HttpServletRequest request)
String key = getKey(request);
return key == null ? null : tokenRepository.get(key);
private String getKey(HttpServletRequest request)
return request.getHeader("Authorization");
private String createNewToken()
return UUID.randomUUID().toString();
SecurityConfig.java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Inject
private CustomCsrfTokenRepository customCsrfTokenRepository;
@Override
protected void configure(HttpSecurity http) throws Exception
http
// .addFilterAfter(new CsrfTokenGeneratorFilter(), CsrfFilter.class)
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.formLogin()
.loginProcessingUrl("/app/authentication")
.successHandler(ajaxAuthenticationSuccessHandler)
.failureHandler(ajaxAuthenticationFailureHandler)
.usernameParameter("j_username")
.passwordParameter("j_password")
.permitAll()
.and()
.csrf()
.csrfTokenRepository(customCsrfTokenRepository)
.and()
如何干净地覆盖标头名称而不是创建自定义 csrfTokenRepository?
我是否需要对单页进行任何其他配置更改 AngularJS 等应用程序,因为它还不能工作。
【问题讨论】:
【参考方案1】:当为 Spring Security 使用 Java 配置时,以下应该是可能的:
public void configure(final HttpSecurity http) throws Exception
final HttpSessionCsrfTokenRepository tokenRepository = new HttpSessionCsrfTokenRepository();
tokenRepository.setHeaderName("X-XSRF-TOKEN");
http.csrf().csrfTokenRepository(tokenRepository);
复杂之处在于单页应用程序依赖于 AJAX,并且在 AJAX 请求中包含 CSRF 令牌有点复杂。使用 AngularJS 时,服务器应在第一次请求以及用户登录或注销时发送一个名为 XSRF-TOKEN
的会话 cookie。然后,AngularJS 将在 HTTP 标头 X-XSRF-TOKEN
中返回此 cookie 的值以及所有请求,然后服务器可以对其进行检查。
【讨论】:
我看到人们使用过滤器在响应标头中发送 cookie。示例github.com/aditzel/spring-security-csrf-filter/blob/master/src/… 和 spring 文档“有人可能会问为什么预期的 CsrfToken 没有存储在 cookie 中。这是因为存在已知的漏洞,其中标头(即指定 cookie)可以由另一个域设置”。您是否有一个示例表明 spring 在“会话 Cookie”中发送回 CSRF 令牌? 正如您所提到的,Spring Security 不提供对在 cookie 中设置 CSRF 令牌的开箱即用支持。编写过滤器是最好的方法。 请检查此线程***.com/questions/31293303/…中的组合答案@以上是关于将 AngularJS 与 SpringSecurity3.2 一起用于 CSRF的主要内容,如果未能解决你的问题,请参考以下文章
将 AngularJS 与 SharePoint WebParts 一起使用时推荐的方法是啥
如何将 Apache Shiro 与 AngularJS 集成
Angularjs + Typescript,如何将 $routeParams 与 IRouteParamsService 一起使用