Spring Security 未创建 CSRF 令牌

Posted

技术标签:

【中文标题】Spring Security 未创建 CSRF 令牌【英文标题】:Spring Security not creating CSRF token 【发布时间】:2019-07-20 13:41:21 【问题描述】:

我希望使用 Spring Security(版本 5.1.2)为我的 Angular 7 应用程序生成 CSRF 令牌。我的 SecurityConfig 文件中有以下内容:

@Override
protected void configure(HttpSecurity http) throws Exception 
    http.cors().and()
            .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());

在我的控制器中使用以下 RequestMapping:

@RestController
@RequestMapping("/authentication")
public class AuthenticationController 

    @GetMapping("/csrf")
    public void getCsrfToken()...

    @PostMapping("/register")
    public RegisterOutputDTO register(@RequestBody UserDTO input)...

我从各种来源收集到csrfTokenRepository 会在我的第一次GET 调用(这是/authentication/csrf 的用途)中自动生成一个带有标题XSRF-token 的cookie,但我没有从那里得到cookie服务器。因此,在我的下一个POST 电话中,我收到了 403 响应。我可能会错过什么?

【问题讨论】:

只有在 cookie XSRF-TOKEN 丢失时才会创建它。查看请求标头以查看它是否已经存在。 @Andreas 我也想过这个,但我没有在标题中发送任何这样的标记。我可以在 Chrome 的应用程序选项卡中看到该 cookie 不存在。 我相信我已经找到了答案。似乎无法跨域发送 cookie。我的 Angular 应用程序托管在 localhost:3000 上,而我的 Java 后端托管在 localhost:9080 上。看来我的选择是以某种方式将它们部署在同一个域上或使用代理。来源:***.com/questions/48002670/… 【参考方案1】:

正如我的问题的 cmets 所示,我找到了问题的答案。 无法跨域发送cookie。

我的前端部署在localhost:3000 上,我的后端部署在localhost:9080 上,显然它们被认为是不同的域。如果我转到localhost:9080(我得到一个白页,但这没关系)然后我转到 Chrome 中的应用程序选项卡,我发现我正在寻找的 XSRF cookie 就像我一直期待的那样存储.该 cookie 可从我从前端执行的 GET 调用中获得。问题是 cookie 需要对 localhost:3000 可用,这样 Angular 才能使用 cookie。

您可以通过多种方式在本地环境中解决此问题。

使用代理

您可以使用代理将某些 url 路径映射到您的后端。这是我采用的解决方案。

我使用 webpack 开发服务器运行我的 Angular 应用程序。 Webpack 提供了一种将某些 url 代理到后端的简单方法。例如:

devServer: 
    contentBase: path.join(__dirname, 'dist'),
    compress: true,
    port: 3000,
    proxy: 
        '/api': 'http://localhost:9080'
    

Angular 应用程序在localhost:3000 上运行。对localhost:3000/api/* 的任何呼叫。将被转发到localhost:9080/api/*。所以就我而言,我不再对localhost:9080/api/authentication/csrf 执行GET 调用,而是调用localhost:3000/api/authentication/csrf,然后将其转发到我的后端。 (对于那些想知道的人,我将 /api 添加到我的休息控制器的路径中。)

在同一个端口上部署两个应用程序

使用frontend-maven-plugin,您可以将前端构建到其 dist 文件夹,然后让 maven 将 dist 文件夹与后端一起打包以进行部署。我还没有尝试过,但是有各种资源表明这应该很容易通过 Spring boot 完成。所以前端和后端都可以通过localhost:9080 使用。

使用 Spring Profile 在本地禁用 csrf

您可以使用 Spring @Profile 注释为本地环境和其他环境(测试、验收、生产)创建不同的配置。可以简单地禁用 Csrf 以进行开发。我不喜欢这个选项,因为我喜欢尽可能保持 DEV 和其他环境相同。这也不是问题陈述的真正答案。

Special thanks to the answer of user @dspies which helped me find the problem.

【讨论】:

我在本地也有一个非常相似的设置,但是 Spring 正在发送 XSRF 令牌,而 Angular 将它发送回 Spring 就好了。我对这个答案很困惑。

以上是关于Spring Security 未创建 CSRF 令牌的主要内容,如果未能解决你的问题,请参考以下文章

CSRF 令牌未正确更新(Ionic + Spring Security)

Spring Security 的 POST 响应标头中未设置 Angular 2 CSRF cookie

无法使用 Spring Security 创建 CSRF 令牌

使用带有 Spring Security 的 Vaadin 出现 403 CSRF 令牌错误

Spring Security Oauth2 : Possible CSRF detected

Spring-Security对CSRF攻击的支持