带有Spring和Angular 2的CSRF

时间:2016-10-11 11:25:42

标签: java spring cookies angular

我正在尝试使用Spring Security(4.1.3)和Angular 2.0.1

实现CSRF保护

相关主题有很多来源,但我找不到明确的指示。有些陈述甚至互相矛盾。

我读到了关于spring的方式(尽管指南描述了Angular 1方式)Spring Security Guide with Angular IT意味着,用          .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());

一切都应该有效"开箱即用"。 更进一步,angular guide to security将CSRF保护描述为内置。

在我的环境中,POST看起来像这样:

  • 有一个OPTIONS-call,它返回POST,200 OK和一个XSRF-TOKEN-cookie。
  • 我的http.post添加了一个授权标题,并添加了RequestOption" withCredentials"
  • 它发送三个cookie,两个JSessionID和一个XSRF-TOKEN,它与OPTIONS-call收到的不同,没有XSRF-header。
  • 调试Spring CsrfFilter向我展示它查找名为X-XSRF-TOKEN的标头,并将其与名为XSRF-TOKEN的cookie中的标记进行比较。

为什么Angular也没有发送标题? 如果Spring只检查提供的cookie和提供的标头而没有任何服务器端操作,那么这是如何安全的?

有一些类似的问题,比如this但是0赞成的唯一答案似乎(对我来说)是完全错误的,因为根据我的理解,CSRF必须对服务器进行cookie验证检查。

This问题仅提供有关如何更改Cookie或标题名称的信息,如here所述

我在这里缺少什么?我怀疑Spring Security实现中是否存在错误,但我无法让它工作。

有什么想法吗?

POST-call

login(account: Account): Promise<Account> {  


   let headers = new Headers({ 'Content-Type': 'application/json' });
    headers.append('X-TENANT-ID', '1');
    headers.append('Authorization', 'Basic ' + btoa(account.userName + ':' + account.password));
    let options = new RequestOptions({ headers: headers, withCredentials:true });
   return this.http.post(this.loginUrl, account, options).toPromise()
  .then(this.extractData)
  .catch(this.handleError)

}

Spring Security Config

 [] csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())

OPTIONS header

POST header

1 个答案:

答案 0 :(得分:0)

问题是应用程序路径。 Spring可以选择在其管道中设置cookie路径,但它尚未发布。

我必须为CsrfTokenRepository编写自己的实现,它将接受不同的cookie路径。

这些是相关的部分:

public final class CookieCsrfTokenRepository implements CsrfTokenRepository

private String cookiePath;

 @Override
public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) {
    String tokenValue = token == null ? "" : token.getToken();
    Cookie cookie = new Cookie(this.cookieName, tokenValue);
    cookie.setSecure(request.isSecure());
    // cookie.setPath(getCookiePath(request));
    if (this.cookiePath != null && !this.cookiePath.isEmpty()) {
        cookie.setPath(this.cookiePath);
    } else {
        cookie.setPath(getRequestContext(request));
    }

    if (token == null) {
        cookie.setMaxAge(0);
    } else {
        cookie.setMaxAge(-1);
    }
    if (cookieHttpOnly && setHttpOnlyMethod != null) {
        ReflectionUtils.invokeMethod(setHttpOnlyMethod, cookie, Boolean.TRUE);
    }

    response.addCookie(cookie);
}

public void setCookiePath(String path) {
    this.cookiePath = path;
}

public String getCookiePath() {
    return this.cookiePath;
}