为什么启用 csrf 时会出现 401 错误?

Why do I get a 401 error when I enable csrf?

所以我正在开发我的第一个全栈应用程序(spring boot rest API 和 Vue.js 前端),我在使用 sonarqube 时遇到了一个问题。 我的 sonarqube 发出以下警告:

确保在此处禁用 Spring 安全的 CSRF 保护是安全的。

它来自这个文件:

@Configuration
@AllArgsConstructor
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class
WebSecurityConfig extends WebSecurityConfigurerAdapter {//provides security for endpoints

    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Autowired
    private UserDetailsService jwtUserDetailsService;

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    private final AccountService accountService;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        // configure AuthenticationManager so that it knows from where to load
        // user for matching credentials
        // Use BCryptPasswordEncoder
        auth.userDetailsService(jwtUserDetailsService).passwordEncoder(bCryptPasswordEncoder);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf()/*.disable()*/.and()//So we can send post requests without being rejected(if we using form based indication we want to enable this)
                .authorizeRequests()
                .antMatchers("/login", "/authenticate","/register", "/register/**")
                .permitAll()//any request that goes trough that end point we want to allow.
                .anyRequest()
                .authenticated().and().exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
        http.cors();
        http.logout().permitAll();
        http.logout().logoutSuccessHandler((new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK)));

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(daoAuthenticationProvider());
    }

    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider() {
        DaoAuthenticationProvider provider =
                new DaoAuthenticationProvider();
        provider.setPasswordEncoder(bCryptPasswordEncoder);
        provider.setUserDetailsService(jwtUserDetailsService);
        return provider;
    }
}

更具体的这段代码:

  @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .csrf()/*.disable()*/.and()//So we can send post requests without being rejected(if we using form based indication we want to enable this)
                    .authorizeRequests()
                    .antMatchers("/login", "/authenticate","/register", "/register/**")
                    .permitAll()//any request that goes trough that end point we want to allow.
                    .anyRequest()
                    .authenticated().and().exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
                    .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and().addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
            http.cors();
            http.logout().permitAll();
            http.logout().logoutSuccessHandler((new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK)));

当我删除第一个 .and() 并使用禁用(现在已注释掉)时,我的程序可以运行,但我想找到一个可以 .csrf() 启用的解决方案(我知道它是标准启用的)并且我的登录停止给我一个 401 错误。

提前致谢!

显然,您正在使用 JWT 对请求进行身份验证。这通常不涉及 cookie(令牌通常作为请求 headers 发送)。如果你是这种情况(JWT 在 header 中收到)你可以忽略 Sonarqube 警告,你不需要 CSRF 保护。

原因是 CSRF 是一种攻击,当受害者访问恶意网站时,攻击者利用受害者用户的现有 session。这是基于浏览器随请求发送的 cookie 仅取决于目的地,而不取决于来源(即 attacker.com 上的 javascript 可以向 victim.com 发出请求,并且victim.com 的用户 cookie 将自动发送)。如果请求 headers 用于传输令牌,则攻击者无法在其恶意域上访问该令牌。

如果您仍然想让它工作(因为例如您的 JWT 确实是从 cookie 接收到的),您将必须从您的前端 (VueJS) 为每个不是 get 的请求发送正确的 CSRF 令牌,所以这是对你的前端的改变,而不是你的后端。