es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo agregar el token CSRF al encabezado HTTP utilizando la API fetch y VanillaJS

Estoy tratando de enviar una solicitud POST a un servidor que está configurado para usar Spring Security. Al enviar mi solicitud, obtengo un error 403. Este problema se debe a la protección CSRF. Cuando desactivo CSRF en mi configuración de Spring Security, la solicitud POST funciona correctamente.

Estoy usando la API fetch para enviar mi solicitud POST. Esto permite especificar la cabecera HTTP que acompaña al cuerpo que contiene mi objeto JSON que estoy tratando de enviar. Ahora estoy tratando de agregar el token CSRF a mi cabecera HTTP. Con este propósito, he agregado las siguientes dos etiquetas meta a la sección de encabezado de mi HTML:

<meta name="_csrf" content="${_csrf.token}">
<meta name="_csrf_header" content="${_csrf.headerName}">

Luego, he agregado las siguientes líneas a mi JavaScript:

const token = document.querySelector('meta[name="_csrf"]').content;
const header = document.querySelector('meta[name="_csrf_header"]').content;

let responsePromise = fetch(
    "myEndpoint",
    { method: 'POST', headers: {'Content-Type': 'application/json', header: token}, body: JSON.stringify(myJSON) });
})

Asumo que Spring Security completa el contenido de mi token CSRF. Sin embargo, el mensaje de error aún persiste. Creo que podría no haber nada dentro de mi etiqueta meta _csrf. Cuando registro el contenido (token y header), solo recibo:

${_csrf.headerName}
${_csrf.token}

Mientras espero ver el nombre de encabezado “X-CSRF-Token” y el token real. ¿Podría ser que Spring Security no complete automáticamente este contenido?

======= Actualización:

Mi proyecto es un proyecto Maven. He agregado la dependencia Thymeleaf a mi archivo pom.xml. No sé mucho sobre Thymeleaf, pero parecía ser la forma más fácil de implementar el mecanismo de inicio de sesión con Spring Security. De todos modos, cuando reemplazo content con th:content en mis etiquetas meta, el encabezado y el token se encuentran y se registran en mi consola. Sin embargo, aún no puedo enviar mi solicitud POST, el error 403 persiste.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Solución para enviar una solicitud POST a un servidor utilizando Spring Security con protección CSRF

    Cuando se trabaja con Spring Security y protección CSRF, enviar una solicitud POST podría resultar en un error 403. Deshabilitar la protección CSRF puede no ser la mejor solución, ya que puede comprometer la seguridad de la aplicación. Se pueden seguir los siguientes pasos para agregar el token CSRF al encabezado HTTP mientras se utiliza la API fetch:

    1. Asegúrese de que se genere el token CSRF y se agregue al modelo en el lado del servidor. Esto se puede hacer utilizando el CsrfTokenRepository de Spring Security. El token debe agregarse con la clave _csrf y el nombre del encabezado debe agregarse con la clave _csrf_header.
      @Autowired
      private CsrfTokenRepository csrfTokenRepository;
      
      @GetMapping("/login")
      public String login(Model model) {
         CsrfToken csrfToken = csrfTokenRepository.generateToken(request);
         model.addAttribute("_csrf", csrfToken.getToken());
         model.addAttribute("_csrf_header", csrfToken.getHeaderName());
         return "login";
      }
      
    2. En la sección <head> del HTML, agregue las siguientes etiquetas meta para poblar el token CSRF y el nombre del encabezado:
      <meta name="_csrf" th:content="${_csrf}">
      <meta name="_csrf_header" th:content="${_csrf_header}">
      

      Tenga en cuenta que se utiliza el atributo th:content en lugar del atributo content, ya que esto permite a Thymeleaf poblar los valores del token y del encabezado.

    3. En JavaScript, obtenga los valores del token y del encabezado de las etiquetas meta y utilícelos para construir el encabezado HTTP de la solicitud fetch:

      const token = document.querySelector('meta[name="_csrf"]').getAttribute('content');
      const header = document.querySelector('meta[name="_csrf_header"]').getAttribute('content');
      const headers = new Headers();
      headers.append(header, token);
      
      const responsePromise = fetch("miEndpoint", {
         method: 'POST',
         headers: headers,
         body: JSON.stringify(miJSON)
      });
      

      Tenga en cuenta que se utiliza el objeto Headers para construir el objeto de encabezados de la solicitud fetch. Esto nos permite establecer el nombre y el valor del encabezado, correspondiendo a los valores obtenidos de las etiquetas meta.

    Con estos pasos implementados, el token CSRF se incluirá en el encabezado HTTP de la solicitud fetch, lo que permitirá autenticar la solicitud mediante Spring Security.

Comments are closed.