为什么我启用 csrf 时收到 401 错误?

Lar*_*sse 5 security csrf http-status-code-401 spring-boot

因此,我正在开发我的第一个全栈应用程序(Spring Boot Rest API 和 Vue.js 前端),并且我在使用 sonarqube 时遇到了一个问题。我的声纳发出以下警告:

确保在这里禁用 Spring Security 的 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

更具体地说,这段代码:

  @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)));
Run Code Online (Sandbox Code Playgroud)

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

提前致谢!

Gab*_*yel 8

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

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

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