Se encontró un token CSRF no válido 'nulo' en el parámetro de solicitud '_csrf' o en el encabezado 'X-CSRF-TOKEN'

90

Después de configurar Spring Security 3.2, _csrf.tokenno está vinculado a una solicitud o un objeto de sesión.

Esta es la configuración de seguridad de 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>

El archivo 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>

Y muestra el siguiente html:

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

El resultado es el estado HTTP 403:

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

ACTUALIZACIÓN Después de una depuración, el objeto de solicitud sale bien de DelegatingFilterProxy, pero en la línea 469 de CoyoteAdapter ejecuta request.recycle (); que borra todos los atributos ...

Pruebo en Tomcat 6.0.36, 7.0.50 con JDK 1.7.

No he entendido este comportamiento, en lugar de, sería posible si alguien me indicara alguna guerra de muestra de aplicación con Spring Security 3.2 que funciona con CSRF.

Hugo Robayo
fuente
1
¿Qué versión de Spring usas? Esto mismo funciona para mí (sin embargo, hay diferencias en spring-security.xml) con Spring 4.0.0 RELEASE (GA), Spring Security 3.2.0 RELEASE (GA) (aunque está integrado con Struts 2.3.16. No le di un intente con Spring MVC solo). Sin embargo, falla cuando la solicitud es de varias partes para cargar archivos con el estado 403. Estoy luchando por encontrar una solución.
Diminuto
Spring 3.2.6, Spring Security 3.2.0, el CSRF, el token se agregó al objeto de solicitud http, el objeto de sesión es el mismo junto con el hilo de solicitud, pero cuando se apaga hasta que se procesa, el jsp elimina todos los atributos y solo dejar un atributo ... filter_applied
Hugo Robayo
@Tiny: ¿Alguna vez encontró una solución al problema de varias partes? Tengo exactamente el mismo problema.
Rob Johansen
1
@AlienBishop: Sí, consulte esta respuesta (utiliza una combinación de Spring y Struts). Si solo tiene Spring MVC, consulte esta respuesta. Cabe señalar que el orden de los filtros web.xmles crucial. MultipartFilterdebe declararse antes springSecurityFilterChain. Espero que ayude. Gracias.
Diminuto

Respuestas:

110

Parece que la protección CSRF (Cross Site Request Forgery) en su aplicación Spring está habilitada. En realidad está habilitado por defecto.

Según spring.io :

¿Cuándo debería utilizar la protección CSRF? Nuestra recomendación es utilizar la protección CSRF para cualquier solicitud que pueda ser procesada por un navegador por usuarios normales. Si solo está creando un servicio que es utilizado por clientes que no son navegadores, es probable que desee desactivar la protección CSRF.

Entonces, para deshabilitarlo:

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

Sin embargo, si desea mantener habilitada la protección CSRF, debe incluir en su formulario el csrftoken. Puedes hacerlo así:

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

Incluso puede incluir el token CSRF en la acción del formulario:

<form action="./upload?${_csrf.parameterName}=${_csrf.token}" method="post" enctype="multipart/form-data">
MaVRoSCy
fuente
2
Esto debe aceptarse como la respuesta porque explica no solo qué hacer, sino también lo que debe considerar antes de hacer algo para detener estos errores.
Thomas Carlisle
1
También puede hacerlo.csrf().ignoringAntMatchers("/h2-console/**")
insan-e
En la respuesta anterior, evite pasar por el estilo de parámetro de consulta. Si hace esto, está exponiendo tokens en público.
Pramod S. Nikam
31

¿No debería agregar al formulario de inicio de sesión ?;

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

Como se indica aquí en la documentación de seguridad de Spring

borjab
fuente
12

Si aplica security="none", no se generará ningún token csrf. La página no pasará por el filtro de seguridad. Utilice el rol ANÓNIMO.

No he entrado en detalles, pero me está funcionando.

 <http auto-config="true" use-expressions="true">
   <intercept-url pattern="/login.jsp" access="hasRole('ANONYMOUS')" />
   <!-- you configuration -->
   </http>
Awanish Kumar
fuente
Estaba usando security = none y pasar a su respuesta resolvió este problema. es increíble thymeleaf agrega automáticamente el token csrf. Gracias !
rxx
7

Trate de cambiar esta situación: <csrf /> a esto: <csrf disabled="true"/>. Debería deshabilitar csfr.

Arkadiusz Gibes
fuente
7

Con la hoja de tomillo puedes agregar:

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

Yo solia tener el mismo problema.

Su configuración usa security = "none", por lo que no puede generar _csrf:

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

puede configurar access = "IS_AUTHENTICATED_ANONYMOUSLY" para la página /login.jsp reemplazar la configuración anterior:

<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
fuente
1

Consulte mi aplicación de muestra de trabajo en Github y compárela con su configuración.

manish
fuente
Bajaré a Spring 3.2.6, espero que funcione sin Spring MVC.
Hugo Robayo
Sí, debería funcionar sin problemas ya que creé la aplicación de muestra a partir de mi aplicación existente que estaba en Spring 3.1.4.
manish
ja, ja, ja, ja, genial, para que funcione, simplemente degradar no es una solución bhaiya ji @manish
Kuldeep Singh
1

Ninguna de las soluciones funcionó para mí. El único que funcionó para mí en forma de primavera es:

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

REEMPLAZADAS CON:

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

(Spring 5 con csrf habilitado en la configuración de java)

vancho
fuente
0

En su controlador agregue lo siguiente:

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

Y en la página jsp agregue

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