J'utilise la sécurité de printemps avec Java config
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/*").hasRole("ADMIN")
.and()
.addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class)
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.formLogin()
.successHandler(authenticationSuccessHandler)
.failureHandler(new SimpleUrlAuthenticationFailureHandler());
J'utilise PostMan pour tester mes REST services. Je reçois le 'jeton csrf' avec succès et je peux me connecter en utilisant X-CSRF-TOKEN
dans l'en-tête de la demande. Mais après la connexion lorsque je clique sur la demande de publication (j'inclus le même jeton dans l'en-tête de demande que j'ai utilisé pour la demande de connexion), le message d'erreur suivant s'affiche:
Statut HTTP 403 - Impossible de vérifier le jeton CSRF fourni car votre session n'a pas été trouvée.
Quelqu'un peut-il me guider sur ce que je fais mal?.
Selon spring.io:
Quand devriez-vous utiliser la protection CSRF? Notre recommandation est d'utiliser la protection CSRF pour toute demande pouvant être traitée par un navigateur par des utilisateurs normaux. Si vous créez uniquement un service utilisé par des clients autres que des navigateurs, vous souhaiterez probablement désactiver la protection CSRF.
Donc pour le désactiver:
@Configuration
public class RestSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
Remarque: La protection CSRF est activée par défaut avec Java Configuration
essayez ceci: @Override protected boolean sameOriginDisabled() { return true;}
@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
...
// Determines if a CSRF token is required for connecting. This protects against remote
// sites from connecting to the application and being able to read/write data over the
// connection. The default is false (the token is required).
@Override
protected boolean sameOriginDisabled() {
return true;
}
}
Désactiver la protection CSRF est une mauvaise idée.
Spring générera automatiquement un nouveau jeton CSRF après chaque demande et vous devrez l'inclure dans toutes les demandes HTTP ayant des effets secondaires (PUT, POST, PATCH, DELETE).
Dans Postman, vous pouvez utiliser un test dans chaque demande pour stocker le jeton CSRF de manière globale, par exemple. en utilisant CookieCsrfTokenRepository
pm.globals.set("xsrf-token", postman.getResponseCookie("XSRF-TOKEN").value);
Et puis l'inclure comme un en-tête avec la clé X-XSRF-TOKEN
et valeur {{xsrf-token}}
.
Entré à la même erreur juste avec POST, obtenait 403 interdit] "Impossible de vérifier le jeton CSRF fourni car votre session n'a pas été trouvée."
Après avoir exploré la solution trouvée, ajoutez l’annotation @EnableResourceServer à config.
La configuration ressemble à ça (spring-boot.version -> 1.4.1.RELEASE, spring-security.version -> 4.1.3.RELEASE, spring.version -> 4.3.4.RELEASE)
@Configuration
@EnableWebSecurity
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends ResourceServerConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(inMemoryUserDetailsManager()).passwordEncoder(passwordEncoder());
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.httpBasic();
http.sessionManagement().sessionCreationPolicy(STATELESS);
http.csrf().disable();
http.authorizeRequests().anyRequest()
.permitAll();
}
private InMemoryUserDetailsManager inMemoryUserDetailsManager() throws IOException {
// load custom properties
Properties properties = new Properties();
return new InMemoryUserDetailsManager(properties);
}
private PasswordEncoder passwordEncoder() {
return new TextEncryptorBasedPasswordEncoder(textEncryptor());
}
private TextEncryptor textEncryptor() {
return new OpenSslCompatibleTextEncryptor();
}
}
Je reçois ce message d'erreur (HTTP Status 403 - Could not verify the provided CSRF token because your session was not found.
) quand je fais un appel JS fetch AJAX sans utiliser le credentials: "same-Origin"
option.
Mauvaise façon
fetch(url)
.then(function (response) { return response.json(); })
.then(function (data) { console.log(data); })
manière correcte
fetch(url, {
credentials: "same-Origin"
})
.then(function (response) { return response.json(); })
.then(function (data) { console.log(data); })
C'est une vieille question, mais cela pourrait aider quelqu'un. J'ai eu le même problème et c'est comme ça que j'ai pu le résoudre.
Pour que la CSRF fonctionne avec l'API REST, vous devez obtenir un jeton CSRF via l'API avant chaque appel et utiliser ce jeton. Le jeton est différent à chaque fois et ne peut pas être réutilisé.
Voici le contrôleur pour obtenir le jeton CSRF:
@RequestMapping(value = "/csrf", method = RequestMethod.GET)
public ResponseEntity<CSRFDTO> getCsrfToken(HttpServletRequest request) {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
return ResponseEntity.ok(CSRFDTO.builder()
.headerName(csrf.getHeaderName())
.token(csrf.getToken())
.build());
}
En outre, vous pouvez envisager de configurer votre application Spring pour désactiver le CSRF pour les noeuds finaux d'API REST. Pour citer un article que j'ai lu quelque part:
Je suis très certain que les jetons CSRF sur un REST extrémité n'accordent aucune protection supplémentaire. Ainsi, l'activation de la protection CSRF sur un REST introduit uniquement du code inutile. à votre application, et je pense que cela devrait être omis.
J'espère que cela t'aides.