Token CSRF inválido 'null' encontrado no parâmetro de solicitação '_csrf' ou cabeçalho 'X-CSRF-TOKEN'

90

Depois de configurar o Spring Security 3.2, _csrf.tokennão está vinculado a uma solicitação ou a um objeto de sessão.

Esta é a configuração de segurança da primavera:

<http pattern="/login.jsp" security="none"/>

<http>
    <intercept-url pattern="/**" access="ROLE_USER"/>
    <form-login login-page="/login.jsp"
                authentication-failure-url="/login.jsp?error=1"
                default-target-url="/index.jsp"/>
    <logout/>
    <csrf />
</http>

<authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="test" password="test" authorities="ROLE_USER/>
        </user-service>
    </authentication-provider>
</authentication-manager>

O arquivo login.jsp

<form name="f" action="${contextPath}/j_spring_security_check" method="post" >
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
    <button id="ingresarButton"
            name="submit"
            type="submit"
            class="right"
            style="margin-right: 10px;">Ingresar</button>
    <span>
        <label for="usuario">Usuario :</label>
        <input type="text" name="j_username" id="u" class="" value=''/>
    </span>
    <span>
        <label for="clave">Contrase&ntilde;a :</label>

        <input type="password"
               name="j_password"
               id="p"
               class=""
               onfocus="vc_psfocus = 1;"
               value="">
    </span>
</form>

E ele renderiza o próximo html:

<input type="hidden" name="" value="" />

O resultado é o status HTTP 403:

Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.

UPDATE Depois de alguma depuração, o objeto de solicitação sai de forma fina DelegatingFilterProxy, mas na linha 469 de CoyoteAdapter ele executa request.recycle (); que apaga todos os atributos ...

Testo no Tomcat 6.0.36, 7.0.50 com JDK 1.7.

Eu não entendi esse comportamento, ao invés de, seria possível se alguém me apontasse na direção de alguma guerra de amostra de aplicativo com Spring Security 3.2 que funciona com CSRF.

Hugo Robayo
fonte
1
Qual versão do Spring você usa? Essa mesma coisa funciona para mim (existem diferenças, no entanto, em spring-security.xml) com Spring 4.0.0 RELEASE (GA), Spring Security 3.2.0 RELEASE (GA) (embora seja integrado com Struts 2.3.16. Eu não dei um experimente apenas com Spring MVC). No entanto, ele falha, quando a solicitação é multiparte para upload de arquivos com o status 403. Estou lutando para encontrar uma solução para isso.
Tiny
Spring 3.2.6, Spring Security 3.2.0, o CSRF, token foi adicionado ao objeto http-request, o objeto de sessão é o mesmo junto com o thread de solicitação, mas quando sai até seu render, o jsp remove todos os atributos e apenas deixe um atributo ... filter_applied
Hugo Robayo
@Tiny: Você já encontrou uma solução para o problema de várias partes? Estou tendo exatamente o mesmo problema.
Rob Johansen
1
@AlienBishop: Sim, verifique esta resposta (ela usa uma combinação de Spring e Struts). Se você tiver Spring MVC sozinho, verifique esta resposta. Deve-se notar que a ordem dos filtros web.xmlé crucial. MultipartFilterdeve ser declarado antes springSecurityFilterChain. Espero que ajude. Obrigado.
Tiny

Respostas:

109

Parece que a proteção CSRF (Cross Site Request Forgery) em seu aplicativo Spring está habilitada. Na verdade, ele está habilitado por padrão.

De acordo com spring.io :

Quando você deve usar a proteção contra CSRF? Nossa recomendação é usar proteção CSRF para qualquer solicitação que possa ser processada por um navegador por usuários normais. Se você estiver criando um serviço que é usado apenas por clientes sem navegador, provavelmente desejará desativar a proteção CSRF.

Então, para desativá-lo:

@Configuration
public class RestSecurityConfig extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable();
  }
}

Se você deseja manter a proteção contra CSRF ativada, deverá incluir em seu formulário o csrftoken. Você pode fazer assim:

<form .... >
  ....other fields here....
  <input type="hidden"  name="${_csrf.parameterName}"   value="${_csrf.token}"/>
</form>

Você pode até incluir o token CSRF na ação do formulário:

<form action="./upload?${_csrf.parameterName}=${_csrf.token}" method="post" enctype="multipart/form-data">
MaVRoSCy
fonte
2
Isso deve ser aceito como a resposta porque explica não apenas o que fazer, mas também o que você deve considerar antes de fazer algo para impedir esses erros.
Thomas Carlisle
1
Você também pode fazer.csrf().ignoringAntMatchers("/h2-console/**")
insan-e
Na resposta acima, evite usar o estilo de parâmetro de consulta. Se você fizer isso, estará expondo tokens em público.
Pramod S. Nikam
31

Você não deveria adicionar ao formulário de login ?;

<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> 

Conforme declarado aqui na documentação de segurança do Spring

Borjab
fonte
12

Se você aplicar security="none", nenhum token csrf será gerado. A página não passará pelo filtro de segurança. Use a função ANONYMOUS.

Não entrei em detalhes, mas está funcionando para mim.

 <http auto-config="true" use-expressions="true">
   <intercept-url pattern="/login.jsp" access="hasRole('ANONYMOUS')" />
   <!-- you configuration -->
   </http>
Awanish Kumar
fonte
Eu estava usando o security = none e passando para sua resposta resolveu esse problema. é incrível que o thymeleaf adiciona automaticamente o token csrf. Obrigado !
rxx
7

Tente mudar isto: <csrf /> a isto: <csrf disabled="true"/>. Deve desativar o csfr.

Arkadiusz Gibes
fonte
7

Com o thymeleaf você pode adicionar:

<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
Lay Leangsros
fonte
4

Eu costumava ter o mesmo problema.

Sua configuração usa security = "none", portanto não pode gerar _csrf:

<http pattern="/login.jsp" security="none"/>

você pode definir access = "IS_AUTHENTICATED_ANONYMOUSLY" para a página /login.jsp substituir configuração acima:

<http>
    <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <intercept-url pattern="/**" access="ROLE_USER"/>
    <form-login login-page="/login.jsp"
            authentication-failure-url="/login.jsp?error=1"
            default-target-url="/index.jsp"/>
    <logout/>
    <csrf />
</http>
xxg
fonte
2

eu acho que csrf só funciona com formas de mola

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

mude para form:formtag e veja se funciona.

Saurabh Kumar
fonte
Você não precisa usar formulários de primavera: docs.spring.io/spring-security/site/docs/3.2.7.RELEASE/…
Bart Swennenhuis
1

Por favor, veja meu aplicativo de amostra de trabalho no Github e compare com sua configuração.

manish
fonte
Vou fazer o downgrade para o spring 3.2.6, espero que funcione sem o spring mvc.
Hugo Robayo
Sim, deve funcionar sem problemas, pois criei o aplicativo de amostra do meu aplicativo existente que estava no Spring 3.1.4.
manish
ha ha ha ha ha, ótimo, fazê-lo funcionar apenas rebaixando não é a solução bhaiya ji @manish
Kuldeep Singh
1

Nenhuma das soluções funcionou comigo. O único que funcionou para mim na forma de primavera é:

action = "./ upload? $ {_ csrf.parameterName} = $ {_ csrf.token}"

SUBSTITUÍDO POR:

action = "./ upload? _csrf = $ {_ csrf.token}"

(Spring 5 com csrf habilitado na configuração java)

vancho
fonte
0

Em seu controlador, adicione o seguinte:

@RequestParam(value = "_csrf", required = false) String csrf

E na página jsp adicione

<form:form modelAttribute="someName" action="someURI?${_csrf.parameterName}=${_csrf.token}
Taras Melnyk
fonte